CSU--1541-- There is No Alternative

</pre>1541: There is No Alternative</h2><span class="green">Time Limit: </span>3 Sec  <span class="green">Memory Limit: </span>256 MB<span class="green">Submit: </span>259  <span class="green">Solved: </span>67[<a target=_blank href="http://acm.csu.edu.cn/OnlineJudge/submitpage.php?id=1541" target="_blank">Submit</a>][<a target=_blank href="http://acm.csu.edu.cn/OnlineJudge/problemstatus.php?id=1541" target="_blank">Status</a>][<a target=_blank href="http://acm.csu.edu.cn/OnlineJudge/bbs.php?pid=1541" target="_blank">Web Board</a>]</center><h2>Description</h2><div class="content"><p><img alt="" src="http://acm.csu.edu.cn/OnlineJudge/upload/201503/Alternative1.jpg" /> </p></div><h2>Input</h2><div class="content"><p><img width="364" height="43" alt="" src="http://acm.csu.edu.cn/OnlineJudge/upload/201503/Alternative2.jpg" /> <img width="750" height="642" alt="" src="http://acm.csu.edu.cn/OnlineJudge/upload/201503/Alternative3.jpg" /></p></div><h2>Output</h2><div class="content"><p> <img width="758" height="71" alt="" src="http://acm.csu.edu.cn/OnlineJudge/upload/201503/Alternative4.jpg" /></p></div><h2>Sample Input</h2><pre class="content"><span class="sampledata">4 4
1 2 3
1 3 3
2 3 3
2 4 3</span>

Sample Output

1 3


题意:要求构造最小生成树的边中,哪些边是必需的(即删去这条边再构造最小生成树得出的总权值发生了改变),并输出这些边的数目和总权值。

思路:先构造最小生成树,记录总权值sumWeight和使用的边的下标(存入数组used[]),再依次去掉每条边,重新构造最小生成树(注意初始化),比较每次构造的最小生成树的总权值weight,如果与sumWeight不相等,则表示该边不能去掉。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
int flag[55000], n, used[55000];
struct node
{
	int s, d, c;
}road[55000];
bool cmp(const node& a, const node& b)
{
	return a.c<b.c;
}
void init()
{
	for(int i=1; i<=n; i++)
		flag[i]=i;        //初始化根节点为其本身的下标
}
int find(int x)//找该点所属的集合的根节点
{
	return x==flag[x] ? x : flag[x]=find(flag[x]);
}
using namespace std;
int main()
{
#ifdef OFFLINE
	freopen("t.txt","r",stdin);
#endif
	int m, i, j;
	scanf("%d %d", &n, &m);
	i=1;   j=m;
	while(j--){
		scanf("%d %d %d", &road[i].s, &road[i].d, &road[i].c);
		i++;
	}
	sort(road+1, road+i, cmp); //按权值小到大排序
	init();
	int num=0, sumWeight=0, p=1, L, R;
	for(i=1; i<=m; i++){
		L=find(road[i].s), R=find(road[i].d);
		if(L != R){                 //分属两个不同连通分量
			used[p++]=i;       //记录第一次构造最小生成树的边下标
			flag[L]=R;        //改变L的根节点即合并两个集合
			num++;           //统计已加入边的数目
			sumWeight+=road[i].c;
		}
		if(num==n-1)  break;
	}
	int cost=0, weight=0, Num=0;
	for(i=1; i<p; i++){   //依次减去一条边重新构造最小生成树
		weight=0,     num=0, 	init(); //初始化
		for(j=1; j<=m; j++){
			if(j != used[i]){
				L=find(road[j].s), R=find(road[j].d);
				if(L != R){
					num++;  
					flag[L]=R;  
					weight+=road[j].c;
				}
				if(num==n-1)  break;
			}
		}
		if(sumWeight != weight){//不相等说明该边不能省去
			Num++, cost+=road[used[i]].c;//加该边权值(注意该条边下标是used[i])
		}
	}
	printf("%d %d\n", Num, cost);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值