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

 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 }
时间: 2024-10-10 03:29:39

nyoj 修路方案 (判断最小生成树是否唯一)的相关文章

poj 1679 The Unique MST (判断最小生成树是否唯一)

The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20679   Accepted: 7255 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undire

poj 1679 判断最小生成树是否唯一

/* 只需判断等效边和必选边的个数和n-1的关系即可 */ #include<stdio.h> #include<stdlib.h> #define N 110 struct node { int u,v,w; }f[N*N*2]; int cmp(const void *a,const void*b) { return (*(struct node *)a).w-(*(struct node *)b).w; } int pre[N]; int find(int x) { if(x

poj 1679 The Unique MST (判断最小生成树是否唯一)

链接:poj 1679 题意:判断最小生成树是否唯一, 若唯一,输出最小权值和,否则,输出  Not Unique! 判断最小生成树是否唯一的思路: 1.对图中的每一条边,扫描其他边,如果存在相同权值的边,则对该边做标记 2.然后用Kruskal算法或Prim算法求MST 3.求得MST后,如果该MST中未包含做了标记的边,即可判断MST唯一: 如果包含做了标记的边,则依次去掉这些边的一条边,再求MST, 如果求得的MST权值和原来的MST的权值一样,即可判断MST不唯一. 个人思路是先求最小生

POJ 1679 The Unique MST 判断最小生成树是否唯一/次小生成树

题目链接: 1679 题意: 给出 M个点N条边 求它的的最小生成树 不唯一则输出:Not Unique! 题解: prim:判断"最小生成树是否唯一"可以理解为"最小生成树和次小生成树是否相等" 求次小生成树的步骤如下 1)先求出最小生成树T,在prim的同时,用一个矩阵maxx[u][v]记录在树中连接u-v的路径中权值最大的边. 2)枚举所有不在T中的边map[u][v],加入边u-v,删除权值为maxx[u][v]的边; 3)找到MST-maxx[u][v]

POJ 1679 The Unique MST(判断最小生成树是否唯一)

题目链接: http://poj.org/problem?id=1679 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G

poj1679The Unique MST判断最小生成树是否唯一以及求次小生成树边权和的讲解

Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22346   Accepted: 7924 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undirected graph G =

[kuangbin带你飞]专题六 最小生成树 K - The Unique MST (判断最小生成树是否唯一)

K - The Unique MST 题目链接:https://vjudge.net/contest/66965#problem/K 题目: 给定连接的无向图,告诉它的最小生成树是否唯一. 定义1(生成树):考虑连通的无向图G =(V,E). G的生成树是G的子图,比如T =(V',E'),具有以下属性:    1. V'= V.    2.T是连接的和非循环的. 定义2(最小生成树):考虑边加权,连通,无向图G =(V,E). G的最小生成树T =(V,E')是总成本最小的生成树. T的总成本

NYOJ修路方案【次小生成树】

修路方案 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少. 但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧. 输入 第一行输

POJ 1679 The Unique MST (Kruskal 判最小生成树是否唯一)

The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 21646 Accepted: 7661 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undirected