2018百度之星资格赛 1006 三原色图
最小生成树题,比较直观
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int dis[110];//保存最短路径
int pre[110];//并查集
int n,m;
struct edge{
int u,v,w,col,sel;//w为权值,sel为标记该边是否被选,col表示颜色
}e[110];
void init(){
for(int i=1;i<110;i++)
pre[i]=i;
}
int Find(int x){
return pre[x]==x?x:pre[x]=Find(pre[x]);
}
bool cmp(const edge &a,const edge &b){
return a.w<b.w;
}
void mst(int color){ //color为不选的颜色
int cnt=0,cnw=0;//cnt为当前已选的顶点数和-1,cnw表示当前权值和
init();
for(int i=1;i<=m;i++)
e[i].sel=0;
for(int i=1;i<=m&&cnt<n-1;i++){
if(e[i].col==color)
continue;
int fu=Find(e[i].u);
int fv=Find(e[i].v);
if(fu!=fv){
e[i].sel=1;
cnt++;
cnw+=e[i].w;
pre[fv]=fu;
}
}
if(cnt!=n-1)
return;
if(dis[cnt]==-1)
dis[cnt]=cnw;
else
dis[cnt]=min(dis[cnt],cnw);
//上面部分已求出最小生成树,下面部分为从小到大把剩下的边选完
for(int i=1;i<=m;i++){
if(e[i].sel)//表示该边已选过
continue;
else{
cnt++;
cnw+=e[i].w;
if(dis[cnt]==-1)
dis[cnt]=cnw;
else
dis[cnt]=min(dis[cnt],cnw);
}
}
return;
}
int main(){
int T,t=0;
cin>>T;
while(T--){
cin>>n>>m;
memset(dis,-1,sizeof(dis));
for(int i=1;i<=m;i++){
char c;
cin>>e[i].u>>e[i].v>>e[i].w>>c;
if(c=='R') e[i].col=0;
else if(c=='G') e[i].col=1;
else if(c=='B') e[i].col=2;
}
sort(e+1,e+1+m,cmp);//将所有边从小到大排序
mst(0);//分别求出两种情况的最小生成树 0表示不选的颜色
mst(2);//2表示不选的颜色
printf("Case #%d:\n",++t);
for(int i=1;i<=m;++i)
printf("%d\n",dis[i]);
}
return 0;
}