描述
南将军率领着许多部队,它们分别驻扎在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
-
-
题解:其实就是求出来最小生成树外的另外一条最小生成树,第一次求出最小生成树后,我们把每两个点之间的最大值保存下来,因为当我枚举一条没有访问的边时,我可以删除两点路径之间的任意一条边,当我加入该边时,该路径中每个点肯定是可达的。然而我要使得花费最小,所以删除最大边。两点之间最大边可以通过dp算的。每当我访问一个点之后,我就求出访问了的点之间的最大值,即dp[i][j] = max(c[i],dp[j][pre[i]]);i表示刚找到的点,j表示访问过的点。
-
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; const int INF = 0x3fffffff; int map[505][505]; //表示i与j之间的花费 int dp[505][505]; //i与j之间路径花费的最大值 bool used[505][505]; //保存最小生成树的边 bool visited[505]; // int pre[505]; //最小生成树每个点的前驱 int c[505]; //每次更新 int ans; void prim(int n) { ans = 0; memset(visited,false,sizeof(visited)); memset(used,false,sizeof(used)); for(int i = 1;i <= n;i++) //从1开始找 { c[i] = map[1][i]; pre[i] = 1; //所有点的前驱都是1 } visited[1] = true; for(int i = 1;i < n;i++) //找n-1条边 { int min = INF; int k; for(int j = 1;j <= n;j++) //每次在数组中找到最小边 { if(!visited[j] && min > c[j]) { min = c[j]; k = j; } } visited[k] = true; ans += min; used[pre[k]][k] = true; //保存最小生成树的边 used[k][pre[k]] = true; for(int j = 1;j <= n;j++) //更新 { if(visited[j] && k != j) //在访问过的节点中得到两点之间最大边 { dp[k][j] = dp[j][k] = max(c[k],dp[pre[k]][j]); } if(!visited[j] && c[j] > map[k][j]) //更新数组 { c[j] = map[k][j]; pre[j] = k; } } } int maxnum = INF; for(int i = 1;i <= n;i++) { for(int j = i + 1;j <= n;j++) { if(!used[i][j] && map[i][j] != INF) //枚举每一条除了生成树之外的相连的边 { maxnum = min(maxnum,ans - dp[i][j] + map[i][j]); } } } if(maxnum == ans) { cout<<"Yes\n"; } else { cout<<"No\n"; } } int main() { int T; cin>>T; int n,m; int a,b,l; while(T--) { scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { for(int j = 1;j <= n;j++) { if(i == j) { map[i][j] = 0; } else { map[i][j] = INF; //表示没有路 } } } for(int i = 0;i < m;i++) { scanf("%d%d%d",&a,&b,&l); map[a][b] = l; map[b][a] = l; } prim(n); } return 0; }