修路方案
时间限制:3000 ms | 内存限制:65535 KB
难度:5
- 描述
南将军率领着许多部队,它们分别驻扎在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>
using namespace std;
struct edge {
bool flog;
int u,v,val;
} e[200010];
int pre[1000],m,n,minn;
void init() {
for(int i=0; i<1000; i++)
pre[i]=i;
}
int cmp(edge s1,edge s2) {
return s1.val<s2.val;
}
int f(int x) {
return pre[x]==x?x:pre[x]=f(pre[x]);
}
int maxMinTree(int w) {
int sum=0;
for(int i=0; i<m; i++) {
if(i!=w) {
int fx=f(e[i].u);
int fy=f(e[i].v);
if(fx!=fy) {
pre[fx]=fy;
sum+=e[i].val;
}
}
}
int s=f(1);//判断全部的点是不是已经全部连进去
for(int i=2; i<=n; i++)
if(pre[i]!=s)
return -1;
return sum;
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
init();
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].val),e[i].flog=0;
sort(e,e+m,cmp);
minn=0;
//找到最小生成树
for(int i=0; i<m; i++) {
int fx=f(e[i].u);
int fy=f(e[i].v);
if(fx!=fy) {
pre[fx]=fy;
e[i].flog=1;//标记这条边在最小生成树中已经用过
minn+=e[i].val;
}
}
int flag=0;
for(int i=0; i<m; i++) {
//每次排除一条边
if(e[i].flog) {
init();
if(maxMinTree(i)==minn) {
flag=1;
break;
}
}
if(flag) break;
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
}如有错误,欢迎指正~
博客讨论了如何解决NYOJ0118问题,即寻找修路方案。通过构建最小生成树并检查是否存在权值相同的次小生成树来判断是否满足题目条件。提供了相关代码实现。
776

被折叠的 条评论
为什么被折叠?



