您的位置:首页 > 其它

修路方案

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)样例输入
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: