修路方案
2015-11-28 18:35
246 查看
描述
南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。
现在已经知道哪些城市之间可以修路,如果修路,花费是多少。
现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。
但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧。
输入第一行输入一个整数T(1<T<20),表示测试数据的组数
每组测试数据的第一行是两个整数V,E,(3<V<500,10<E<200000)分别表示城市的个数和城市之间路的条数。数据保证所有的城市都有路相连。
随后的E行,每行有三个数字A B L,表示A号城市与B号城市之间修路花费为L。输出对于每组测试数据输出Yes或No(如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)样例输入
样例输出
这道题其实是求最小生成树,我认为用并查集做比较方便一点,
在求最小生成树时可以保存每一条线段,然后删除其中一条再
找一次最小生成树看是否答案一样。
南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。
现在已经知道哪些城市之间可以修路,如果修路,花费是多少。
现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。
但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧。
输入第一行输入一个整数T(1<T<20),表示测试数据的组数
每组测试数据的第一行是两个整数V,E,(3<V<500,10<E<200000)分别表示城市的个数和城市之间路的条数。数据保证所有的城市都有路相连。
随后的E行,每行有三个数字A B L,表示A号城市与B号城市之间修路花费为L。输出对于每组测试数据输出Yes或No(如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)样例输入
2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
样例输出
No Yes
这道题其实是求最小生成树,我认为用并查集做比较方便一点,
在求最小生成树时可以保存每一条线段,然后删除其中一条再
找一次最小生成树看是否答案一样。
#include <stdio.h> #include <string.h> #include <algorithm> #define INF 0x7fffffff const int N = 200005, maxn = 505; int m, father[maxn], n, pos[maxn]; struct node { int A, B, L, flag; friend bool operator < ( node n1, node n2 ) //根据长度排序 { return n1.L < n2.L; } } a ; void init ( ) { for ( int i = 1; i <= n; i ++ ) father[i] = i; } int find ( int x ) //并查集 { int r = x, i, j; while ( r != father[r] ) r = father[r]; i = x; while ( i != r ) { j = father[i]; father[i] = r; i = j; } return r; } int kruskal ( ) { init ( ); int ret = 0, j = 0; //j统计线段的条数 for ( int i = 0; i < m; i ++ ) { if ( a[i].flag ) //标记此线段被删除 continue ; int fx = find ( a[i].A ); int fy = find ( a[i].B ); if ( fx != fy ) { father[fx] = fy; ret = ret+a[i].L; //统计长度和 j ++; } if ( j >= n-1 ) //线段条数为n-1时 证明已经全部找齐 break ; } if ( j < n-1 ) return INF; return ret; } void print ( int n ) { for ( int i = 0; i < n; i ++ ) printf ( "%d ", pos[i] ); printf ( "\n" ); } int main ( ) { int T, cnt, mn, ok; scanf ( "%d", &T ); while ( T -- ) { cnt = mn = ok = 0; scanf ( "%d%d", &n, &m ); for ( int i = 0; i < m; i ++ ) { scanf ( "%d%d%d", &a[i].A, &a[i].B, &a[i].L ); a[i].flag = 0; } std :: sort ( a, a+m ); init ( ); for ( int i = 0; i < m; i ++ ) //不删除点做并查集 { int fx = find ( a[i].A ), fy = find ( a[i].B ); if ( fx != fy ) { father[fx] = fy; mn = mn+a[i].L; pos[cnt ++] = i; //保存最短的线段下标 } if ( cnt >= n-1 ) break ; } //print ( cnt ); for ( int i = 0; i < cnt; i ++ ) { int p = pos[i]; a[p].flag = 1; //删除此点 //printf ( "%d\n", kruskal ( ) ); if ( mn == kruskal ( ) ) { ok = 1; break ; } a[p].flag = 0; //注意还原 } printf ( ok ? "Yes\n" : "No\n" ); } return 0; }
相关文章推荐
- [总结]后缀数组: 注释+模板
- 系统测试过程总结
- 在 Win8 下安装 MongoDB
- 用位域描述float和double值
- SCOPE_IDENTITY的用法
- Preparedstatement和Statement的区别
- C和指针4.4
- Objective-C 类型判断
- HDU 3308 LCIS
- boa.config
- 不能为虚拟电脑 打开一个新任务
- 05_总结一下,以软件开发周期说明不同的测试使用
- Missing Number, First Missing Positive
- 工作周报069
- spark访问hbase
- 51nod 1285 山峰和分段
- JS创建对象的几种方式
- CSS基础学习十八:CSS布局之浮动
- 朝花夕拾——初探Java虚拟机及其加载过程
- c语言字符数组与字符串的使用详解