码迷,mamicode.com
首页 > 其他好文 > 详细

nyoj 修路方案 (判断最小生成树是否唯一)

时间:2015-03-13 09:16:35      阅读:313      评论:0      收藏:0      [点我收藏+]

标签:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 struct node
 7 {
 8     int x, y, dis;
 9     int flag;
10 } a[200010];
11 
12 int cmp(node x, node y)
13 {
14     return x.dis<y.dis;
15 }
16 int father[555], n;
17 
18 int kruskal(int num, int m)
19 {
20     int i, j, k;
21     int ans = 0, cnt = 1;
22     for (i = 0; i<m; i++)
23     {
24         if (i == num)//除去这条边之后再求一次最小生成树
25             continue;
26         int s1 = father[a[i].x];
27         int s2 = father[a[i].y];
28         if (s1 != s2)
29         {
30             ans += a[i].dis;
31             cnt++;
32             father[s2] = s1;
33             for (j = 0; j <= n; j++)
34                 if (father[j] == s2)
35                     father[j] = s1;
36         }
37     }
38     if (cnt != n)
39         return -1;
40     else
41         return ans;
42 }
43 
44 int main()
45 {
46     int m, i, j, t, sum, ans, cnt;
47     scanf("%d", &t);
48     while (t--)
49     {
50         scanf("%d%d", &n, &m);
51         for (i = 0; i <= n; i++)
52             father[i] = i;
53         for (i = 0; i<m; i++)
54         {
55             scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].dis);
56             a[i].flag = 0;
57         }
58         sort(a, a + m, cmp);
59         cnt = 1;
60         ans = 0;
61         for (i = 0; i<m; i++)
62         {
63             int s1 = father[a[i].x];
64             int s2 = father[a[i].y];
65             if (s1 != s2)
66             {
67                 a[i].flag = 1;
68                 ans += a[i].dis;
69                 cnt++;
70                 father[s2] = s1;
71                 for (j = 0; j <= n; j++)
72                     if (father[j] == s2)
73                         father[j] = s1;
74             }
75         }
76         int flag = 0;
77         for (i = 0; i<m; i++)//枚举所有原最小生成树上的边
78         {
79             if (a[i].flag == 0)
80                 continue;
81             sum = 0;
82             for (j = 0; j <= n; j++)//初始化
83                 father[j] = j;
84             sum = kruskal(i, m);
85             if (sum == ans)//与之前的最小生成树比较,如果相等,那么肯定不是唯一的
86             {
87                 flag = 1;
88                 break;
89             }
90         }
91         if (flag)
92             printf("Yes\n");
93         else
94             printf("No\n");
95     }
96 
97     return 0;
98 }

 

另外从网上看到的次小生成树。。 第一次接触

转自http://blog.csdn.net/yhrun/article/details/6916489

 

解题思路:花费最少且任意两个城市能够相同,则说明要求最小生成树。而题目中问是否存在另外一种方案,达到

最小生成树的效果,所以可以采用次小生成树

常用的一种方法就是在求出最小生成树的基础上进行添加边

具体实现:先用prim算法求出最小生成树,并且统计任意一点到其他各点的路径上的最大边权。然后添加改生成树上没有的边(u,v),添加一条边后就会形成环,

然后删除该环中权值大二大的边(即除(u,v)之外的最大权值的边),然后再次统计此时的的费用,如果和最小生生成树的费用相同,则说明存在另外一种方案。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 #include<cstdio>
 6 using namespace std;
 7 #define M 501
 8 int ch1[M][M];   //保存原始边
 9 int ch2[M][M];   //ch2[i][j]表示i到j的路径中的最大比边
10 vector<int> s;   //保存最小生成树的节点
11 int v[M];        //标记访问过的节点
12 int sum=0;
13 void prim(int m,int n)
14 {
15     s.clear();s.push_back(m);v[m]=1;
16     while(s.size()!=n)
17     {
18         int k=200000,x,y;
19         for(int i=0;i<s.size();i++)
20         {
21             int r=s[i];
22             for(int j=1;j<=n;j++)
23             {
24                 if(!v[j]&&ch1[r][j]!=-1)
25                 {
26                     if(k>ch1[r][j])
27                     {
28                         k=ch1[r][j];x=r;y=j;
29                     }
30                 }
31             }
32         }
33         for(int i=0;i<s.size();i++)
34         {
35             if(ch2[s[i]][x]<ch1[x][y])
36             {ch2[y][s[i]]=ch2[s[i]][y]=ch1[x][y];}
37             else {ch2[y][s[i]]=ch2[s[i]][y]=ch2[s[i]][x];}
38         }
39         s.push_back(y);sum+=k;v[y]=1;ch1[x][y]=-1;ch1[y][x]=-1;
40     }
41 }
42 int main()
43 {
44     int N;scanf("%d",&N);
45     while(N--)
46     {
47         int m,n;scanf("%d%d",&m,&n);
48         memset(ch1,-1,sizeof(ch1));memset(ch2,-1,sizeof(ch2));memset(v,0,sizeof(v));
49         for(int i=0;i<n;i++)
50         {
51             int x,y,z;scanf("%d%d%d",&x,&y,&z);
52             ch1[x][y]=z;ch1[y][x]=z;
53             ch2[x][y]=z;ch2[y][x]=z;
54         }
55         prim(1,m);int flat=0;
56         for(int i=1;i<=m;i++)
57         {
58             for(int j=1;j<=m;j++)
59             {
60                 if(ch1[i][j]!=-1)
61                 {
62                     //cout<<i<<"   "<<j<<"   "<<ch1[i][j]<<endl;
63                     //cout<<ch2[i][j]<<endl;
64                     int k=sum-ch2[i][j]+ch1[i][j];
65                     if(k==sum)
66                     {
67                         flat=1;break;
68                     }
69                 }
70             }
71             if(flat)break;
72         }
73         if(flat)cout<<"Yes"<<endl;
74         else cout<<"No"<<endl;
75     }
76 }

 

nyoj 修路方案 (判断最小生成树是否唯一)

标签:

原文地址:http://www.cnblogs.com/usedrosee/p/4334257.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!