-
描述
-
南将军率领着许多部队,它们分别驻扎在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
-
第一行输入一个整数T(1<T<20),表示测试数据的组数
这道题其实是求最小生成树,我认为用并查集做比较方便一点,
在求最小生成树时可以保存每一条线段,然后删除其中一条再
找一次最小生成树看是否答案一样。
#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[N];
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;
}