题目描述
Tyvj 已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着 Tyvj 网站的逐步壮大,管理员的数目也越来越多,现在你身为 Tyvj 管理层的联络员,希望你找到一些通信渠道,使得管理员两两都可以联络(直接或者是间接都可以)。Tyvj 是一个公益性的网站,没有过多的利润,所以你要尽可能的使费用少才可以。
目前你已经知道,Tyvj 的通信渠道分为两大类,一类是必选通信渠道,无论价格多少,你都需要把所有的都选择上;还有一类是选择性的通信渠道,你可以从中挑选一些作为最终管理员联络的通信渠道。数据保证给出的通行渠道可以让所有的管理员联通
输入格式:
第一行 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 表示费用。
输出格式:
最小的通信费用
由于我个人prim用的比较熟所以刚开始做这道题一直企图用prim把它解出来,但是经过一番云雨,我发现prim根本不适合解这道题(╥╯^╰╥),反而用我不是很熟的Kruskal解很快就解出来了。大体思路就是先把必选路径放入最小生成树,然后再找剩下的选择性路径,最后找出最终的最小生成树。
Kruskal代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct data { int x,y,v; }e[20001]; int n,m,father[2001],cnt,ans; int find(int x) { return x==father[x]? x:father[x]=find(father[x]); } bool cmp(data a,data b) { return a.v<b.v; } void un(int x,int y,int v) { father[find(x)]=find(y); ans+=v; } void insert(int x,int y,int v) { cnt++; e[cnt].x=x;e[cnt].y=y; e[cnt].v=v; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) father[i]=i; for(int i=1;i<=m;i++) { int flag,x,y,v; cin>>flag>>x>>y>>v; if(flag==1)un(x,y,v); else insert(x,y,v); } sort(e+1,e+cnt+1,cmp); for(int i=1;i<=cnt;i++) { int x=find(e[i].x),y=find(e[i].y); if(father[x]!=father[y])un(x,y,e[i].v); } cout<<ans; return 0; }