tyvj3412 流言的传播 【最小生成树】

tonyfang posted @ 2015年8月30日 14:45 in 随笔 with tags c++ tyvj , 664 阅读

描述

流言的传播(rumor.pas\c\cpp) 

【题目描述】 
  昨天下午,Matrix67陪MM出去逛街,走累了后去咖啡店歇了歇脚;再后来MM陪Matrix67去了一趟书店,之后两人去电影院看了一场电影。从电影院出来后已经很晚了,考虑到MM的安全问题,Matrix67先送MM回到宿舍,然后自己才回去。第二天Matrix67起床后发现问题严重了:昨天和MM出去玩本来什么都没发生,但现在一些不堪入耳的流言正疯狂传播,很多细节都说得有鼻子有眼的。在澄清事实并抓出元凶的同时,Matrix67希望切断一些流言传播的路径,尽可能减缓流言传播的速度。 
  除去Matrix67和他的MM,学校里还有N个人。这N个人形成了M对双向的朋友关系,这些朋友关系连通了所有N个人。不同的朋友间传递消息的速度各不相同。如果A和B是第i对朋友,那么当其中一个人听到流言后,他会在Ti的时间内传给另一个人。现在,Matrix67只知道流言并没有传遍整个学校,但他不知道哪些人已经听说了这个流言。他希望切断尽可能少的朋友关系,使得无论是哪些人已经获知了流言,流言都无法以原来的速度传给一个新的人(即新的得知此流言的人的出现将变得更晚)。换句话说,Matrix67希望找到一个最小的边集E,使得对任意一个不等于全集的点集S,恰好只有一个顶点在S里的边中权值最小的那一条在边集E中。 

输入格式

  输入文件rumor.in第一行输入两个用空格隔开的正整数N和M,分别表示学校的人数和朋友关系数。 
以下M行每行有三个用空格隔开的正整数,其中第i行的三个正整数为Ai, Bi, Ti,表示Ai和Bi是第i对朋友,它们之间传递消息需要Ti的时间。输入数据保证0

输出格式

  你需要输出你所得到的最小值和具体的方案。 
输出文件rumor.out的第一行是一个正整数,代表你的最优方案中需要切断的朋友关系数。 
以下若干行每行一个正整数,表示你的方案里需要切断的朋友关系在输入数据中的编号(即你需要切断的是输入数据中给的第几条边)。这些数必须按照增序排列输出。 
如果有多种最优方案,你只需要输出其中一种即可。我们的评测系统会自动判断你的输出数据的正确性。 
 

测试样例1

输入

4 4 
1 2 2 
4 3 4 
2 3 3 
1 3 1

输出





4

备注

【样例说明】 
               (1) 
                o 
               / \ 
            1 /   \ 2 
             /     \ 
(4) o-------o-------o (2) 
        4  (3)  3    
  首先,(3)---(4)这条边必须去掉,否则若只有4号同学得知流言,流言将以相同的速度传给下一个人。对于其它三条边,只需要去掉权值较小的两条即可,这样不论获知流言的是哪个(些)人,所有可以继续向外传播流言的边中最小的那一条一定已经被去掉了。可以证明,去掉三条边已经是最优的答案了。 

【数据规模】 
  对于30%的数据,N
  对于50%的数据,N
  对于100%的数据,N

【题解】

观察发现,就是最小生成树啦~

 

# include <stdio.h>
# include <algorithm>
using namespace std;

int n,m;
struct d {
	int u,v,w,id;
}e[1000010];
int cnt=0,a[1000010];
int fa[1000010];
int getf(int x) {
	int r=x;while(fa[r]!=r)r=fa[r];
	int i=x,j;
	while(i!=r)	j=fa[i],fa[i]=r,i=j;
	return r;
}

inline int cmp(d a,d b) {
	return a.w<b.w;
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w),e[i].id=i;
	for(int i=1;i<=n;++i)fa[i]=i;sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;++i) {
		int fu=getf(e[i].u),fv=getf(e[i].v);
		if(fu==fv)continue;
		fa[fu]=fv;a[++cnt]=e[i].id;
		if(cnt==n-1)break;
	}sort(a+1,a+cnt+1);
	printf("%d\n",n-1);
	for(int i=1;i<=cnt;++i)printf("%d\n",a[i]);
}

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter