1947: 联络员
Time Limit: 1 Sec
Memory Limit: 128 MB
64bit IO Format: %lld
Submitted: 15
Accepted: 6
[Submit][Status][Web Board]
Description
Tyvj已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着Tyvj网站的逐步壮大,管理员的数目也越来越多,现在你身为Tyvj管理层的联络员,希望你找到一些通信渠道,使得管理员两两都可以联络(直接或者是间接都可以)。Tyvj是一个公益性的网站,没有过多的利润,所以你要尽可能的使费用少才可以。
目前你已经知道,Tyvj的通信渠道分为两大类,一类是必选通信渠道,无论价格多少,你都需要把所有的都选择上;还有一类是选择性的通信渠道,你可以从中挑选一些作为最终管理员联络的通信渠道。数据保证给出的通行渠道可以让所有的管理员联通。
Input
多组测试数据。
第一行n,m表示Tyvj一共有n个管理员,有m个通信渠道
第二行到m+1行,每行四个非负整数,p,u,v,w 当p=1时,表示这个通信渠道为必选通信渠道;当p=2时,表示这个通信渠道为选择性通信渠道;u,v,w表示本条信息描述的是u,v管理员之间的通信渠道,u可以收到v的信息,v也可以收到u的信息,w表示费用。
Output
Sample Input
5 6
1 1 2 1
1 2 3 1
1 3 4 1
1 4 1 1
2 2 5 10
2 2 5 5
Sample Output
[Submit][Status][Web Board]
题解:
比较水的最小生成树的题。。依旧克鲁斯卡尔算法,只不过先连好一些点罢了
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<string>
#include<stdio.h>
#include<queue>
#include<stack>
#include<map>
#include<deque>
using namespace std;
struct edge
{int f,t;int v;
};
int cmp(edge x,edge y)
{return x.v<y.v;
}
edge a[10005];
int pre[105];
int find(int x)//并查集操作
{if(x!=pre[x])pre[x]=find(pre[x]);return pre[x];
}
int main()
{int i,j,n,d,x,y,w,s,d1,d2,tot,ans,m;while(scanf("%d%d",&n,&m)!=EOF){for(i=1;i<=n;i++)pre[i]=i;s=0;ans=0;tot=0;for(i=0;i<m;i++){scanf("%d%d%d%d",&d,&x,&y,&w);d1=find(x);d2=find(y);if(d==1){if(d1!=d2)//不在一个集合说明两点间加一条通路ans++;s+=w;pre[d2]=d1;}else{a[tot].f=x;a[tot].t=y;a[tot].v=w;tot++;}}sort(a,a+tot,cmp);//贪心排序for(i=0;i<tot;i++){d1=find(a[i].f);d2=find(a[i].t);if(d1!=d2){pre[d2]=d1;s+=a[i].v;ans++;if(ans>=n-1)//连了n-1条边就跑,真刺激break;}}printf("%d\n",s);}return 0;
}