您的位置:首页 > 其它

hdu 2121+4009 最小树形图

2014-05-26 17:51 239 查看
http://www.cppblog.com/RyanWang/archive/2010/01/25/106427.html

简单来说,就是有向的最小生成树:

1、每个点找其最小的入边In[v] ? 如果有除跟节点以外的点找不到入边,则无解 : 否则答案累加In[v]

2、看看有没有环 ? 无环则已经找到解,返回答案 : 将环缩点

3、重新构图,每条边[u->v]的权值减去In[v],然后重复第一步

模板题:

hdu 2121:




View Code

1 #include<iostream>
2 #include<cstring>
3 const int N=1010;
4 const int inf=10000000;
5 using namespace std;
6
7 struct Edge{
8     int u,v,w;
9 }edge[N*N];
10
11 int n,m,ansi;
12 int In
;
13 int visited
,ID
;
14 int pre
;
15
16 //root表示根结点,n是顶点树,m是边数
17 //最小树形图邻接表版本,三步走,找最小入弧,找有向环,缩环为点
18 int Directed_MST(int root,int n,int m){
19     int u,v,i,cnt=0;
20     while(true){
21         //找最小入边
22         for(i=0;i<n;i++)In[i]=inf;
23         for(i=0;i<m;i++){
24             u=edge[i].u;
25             v=edge[i].v;
26             if(edge[i].w<In[v]&&u!=v){
27                 pre[v]=u;//u->v;
28                 if(u==root)//记录是root从哪一条边到有效点的(这个点就是实际的起点)
29                     ansi=i;
30                 In[v]=edge[i].w;
31             }
32         }
33         for(i=0;i<n;i++){
34             if(i==root)continue;
35             if(In[i]==inf)return -1;//说明存在点没有入边
36         }
37         //找环
38         int cntcode=0;
39         memset(visited,-1,sizeof(visited));
40         memset(ID,-1,sizeof(ID));
41         In[root]=0;
42         //标记每一个环
43         for(i=0;i<n;i++){
44             cnt+=In[i];
45             v=i;
46             while(visited[v]!=i&&ID[v]==-1&&v!=root){
47                 visited[v]=i;
48                 v=pre[v];
49             }
50             //说明此时找到一个环
51             if(v!=root&&ID[v]==-1){
52                 //表示这是找到的第几个环,给找到的环的每个点标号
53                 for(u=pre[v];u!=v;u=pre[u]){
54                     ID[u]=cntcode;
55                 }
56                 ID[v]=cntcode++;
57             }
58         }
59         if(cntcode==0)break;//说明不存在环
60         for(i=0;i<n;i++){
61             if(ID[i]==-1)
62                 ID[i]=cntcode++;
63         }
64         //缩点,重新标记
65         for(i=0;i<m;i++){
66             int v=edge[i].v;
67             edge[i].u=ID[edge[i].u];
68             edge[i].v=ID[edge[i].v];
69             //说明原先不在同一个环
70             if(edge[i].u!=edge[i].v){
71                 edge[i].w-=In[v];
72             }
73         }
74         n=cntcode;
75         root=ID[root];
76     }
77     return cnt;
78 }
79
80
81 int main(){
82     while(scanf("%d%d",&n,&m)!=EOF){
83         int sum=0;//添加的虚根点到每个点的权值比所有真实权值总和大1
84         for(int i=0;i<m;i++){
85             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
86             sum+=edge[i].w;
87         }
88         sum++;
89         for(int i=m;i<m+n;i++){
90             edge[i].u=n;//加的虚根点
91             edge[i].v=i-m;
92             edge[i].w=sum;
93         }
94         int ans=Directed_MST(n,n+1,n+m);
95         if(ans==-1||ans>=2*sum){
96             printf("impossible\n");
97         }else
98             printf("%d %d\n",ans-sum,ansi-m);
99         printf("\n");
100     }
101     return 0;
102 }


 hdu4009:




View Code

1 #include<iostream>
2 #include<cstring>
3 const int N = 1010;
4 const int inf=10000000;
5 using namespace std;
6 struct Point{
7     int x,y,z;
8 }p
;
9
10 struct Edge{
11     int u,v,w;
12 }edge[N*N];
13
14 int X,Y,Z;
15 int pre
,ID
,In
,visited
;
16
17 //n表示点数,m表示边数,root表示根
18  int Directed_MST(int root,int n,int m){
19     int u,v,i,cnt=0;
20     while(true)
21     {
22         for(i=0;i<n;i++)In[i]=inf;
23         for(i=0;i<m;i++){
24             u=edge[i].u;
25             v=edge[i].v;
26             if(edge[i].w<In[v]&&u!=v){
27                 pre[v]=u;//找出每个点的最小入弧
28                 In[v]=edge[i].w;
29             }
30         }
31         //除根外有个节点无入弧,就返回false
32         for(i=0;i<n;i++){
33             if(i==root)continue;
34             if(In[i]==inf)return -1;
35         }
36         In[root]=0;
37         int cntcode=0;
38         memset(ID,-1,sizeof(ID));
39         memset(visited,-1,sizeof(visited));
40         for(i=0;i<n;i++){
41             cnt+=In[i];//进行缩圈
42             v=i;
43             while(visited[v]!=i&&ID[v]==-1&&v!=root){
44                 visited[v]=i;
45                 v=pre[v];
46             }
47             if(v!=root&&ID[v]==-1){
48                 for(u=pre[v];u!=v;u=pre[u])
49                     ID[u]=cntcode;
50                 ID[v]=cntcode++;
51             }
52         }
53         if(cntcode==0) break;
54         for(i=0;i<n;i++){
55             if(ID[i]==-1)
56                 ID[i]=cntcode++;
57         }
58         for(i=0;i<m;i++){
59             v=edge[i].v;//进行缩点,重新标记。
60             edge[i].u=ID[edge[i].u];
61             edge[i].v=ID[edge[i].v];
62             if(edge[i].u!=edge[i].v)
63                 edge[i].w-=In[v];
64         }
65         n=cntcode;
66         root=ID[root];
67     }
68     return cnt;
69 }
70
71  int get_cost(Point& a,Point& b){
72     int dis=abs(a.x-b.x)+abs(a.y-b.y)+abs(a.z-b.z);
73     if(a.z>=b.z)
74         return dis*Y;
75     return dis*Y+Z;
76 }
77
78 int main()
79 {
80     int n,m,k,a;
81     while(scanf("%d %d %d %d",&n,&X,&Y,&Z)==4 && (n||X||Y||Z)){
82         m=0;
83         for(int i=1;i<=n;i++)
84             scanf("%d %d %d",&p[i].x,&p[i].y,&p[i].z);
85         for(int i=1;i<=n;i++){
86             scanf("%d",&k);
87             while(k--){
88                 scanf("%d",&a);
89                 edge[m].u=i;
90                 edge[m].v=a;
91                 edge[m++].w=get_cost(p[i],p[a]);
92             }
93         }
94         for(int i=1;i<=n;i++){
95             edge[m].u=0;
96             edge[m].v=i;
97             edge[m++].w=p[i].z*X;
98         }
99         printf("%d\n",Directed_MST(0,n+1,m));
100     }
101     return 0;
102 }


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: