2018百度之星资格赛- 1006 三原色

Problem Description

度度熊有一张 nn 个点 mm 条边的无向图,所有点按照 1,2,\cdots,n1,2,⋯,n 标号,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。

现在度度熊想选出恰好 kk 条边,满足只用这 kk 条边之中的红色边和绿色边就能使 nn 个点之间两两连通,或者只用这 kk 条边之中的蓝色边和绿色边就能使 nn 个点之间两两连通,这里两个点连通是指从一个点出发沿着边可以走到另一个点。

对于每个 k=1,2,\cdots,mk=1,2,⋯,m,你都需要帮度度熊计算选出恰好 kk 条满足条件的边的权值之和的最小值。

Input

第一行包含一个正整数 TT,表示有 TT 组测试数据。

接下来依次描述 TT 组测试数据。对于每组测试数据:

第一行包含两个整数 nn 和 mm,表示图的点数和边数。

接下来 mm 行,每行包含三个整数 a,b,wa,b,w 和一个字符 cc,表示有一条连接点 aa 与点 bb 的权值为 ww、颜色为 cc 的无向边。

保证 1 \leq T \leq 1001≤T≤100,1 \leq n,m \leq 1001≤n,m≤100,1 \leq a,b \leq n1≤a,b≤n,1 \leq w \leq 10001≤w≤1000,c \in {R,G,B}c∈{R,G,B},这里 R,G,BR,G,B 分别表示红色、绿色和蓝色。

Output

对于每组测试数据,先输出一行信息 "Case #x:"(不含引号),其中 x 表示这是第 xx 组测试数据,接下来 mm 行,每行包含一个整数,第 ii 行的整数表示选出恰好 ii 条满足条件的边的权值之和的最小值,如果不存在合法方案,输出 -1−1,行末不要有多余空格。

Sample Input

1
5 8
1 5 1 R
2 1 2 R
5 4 5 R
4 5 3 G
1 3 3 G
4 3 5 G
5 4 1 B
1 2 2 B

Sample Output

Case #1:
-1
-1
-1
9
10
12
17
22

 

这个题目将题目看懂了也很简单, 就是一个一个并查集的应用而已

具体的思路代码里面有

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
typedef struct{
	int x,y,w;//x y 表示连接a b权值为w的边,它是z这个颜色的 
	char z;
}edge;
int t,n,m,ans;//t是指数据的组数,n个点,m条边 
int fa1[110];
int fa2[110];//两种不同情况下的父子情况 
edge e[110];//110条边
vector<edge> v1;
vector<edge> v2;//从大到小分别记录红绿或者蓝绿不能加进来的边的数量 
//  思路: 将所有的边按照权值大小排一遍
//  其后输出n-2个-1.
//  再之后求出红绿和蓝绿的最小连通边权
//  在遍历的同时用两个vector记录不可以加进来的边,到最后一个一个加就行了 
bool cmp(const edge& e1,const edge& e2){
	return e1.w<e2.w;
} 
int find1(int x){
	return (x==fa1[x])?x:(fa1[x]=find1(fa1[x]));
}
int find2(int x){
	return (x==fa2[x])?x:(fa2[x]=find2(fa2[x]));
}
int main(){
	int count=1;
	scanf("%d",&t);
	while(t--){
		scanf("%d %d",&n,&m);
		for(int i=0;i<m;i++){
			scanf("%d %d %d %c",&e[i].x,&e[i].y,&e[i].w,&e[i].z);
		}
		for(int i=1;i<=n;i++){
			fa1[i] = i;
			fa2[i] = i;
		}
		ans = -1;
		v1.clear();
		v2.clear();
		sort(e,e+m,cmp);//按照权值大小排序
		int tx1,tx2,ty1,ty2,tans1=0,tans2=0; //两种不同情况下find到的数值 
		for(int i=0;i<m;i++){ //先将两种不同的情况下的最小连通权值给求出来 
			tx1 = find1(e[i].x);
			ty1 = find1(e[i].y);
			tx2 = find2(e[i].x);
			ty2 = find2(e[i].y);
			if(tx1 != ty1 && (e[i].z=='R'||e[i].z=='G')){
				tans1 += e[i].w;
				fa1[tx1] = ty1;
			}else{
				v1.push_back(e[i]);
			}
			if(tx2 != ty2 && (e[i].z=='B'||e[i].z=='G')){
				tans2 += e[i].w;
				fa2[tx2] = ty2;
			}else{
				v2.push_back(e[i]);
			}
		}
		int f1=0,f2=0;//分别确定两个点是否为连通图 
		for(int i=1;i<=n;i++){
			if(i == find1(i)) f1++;
			if(i == find2(i)) f2++;
		}
		printf("Case #%d:\n",count++);
		ans = -1;
		for(int i=1;i<=m;i++){
			int j = i-n;
			if(j >=0 ){
				tans1 += v1[j].w;
				tans2 += v2[j].w;
			}
			if(i>=n-1&&(f1==1||f2==1)){
				if(f1==1&&f2==1){
					ans = min(tans1,tans2);
				}else if(f1==1){
					ans = tans1;
				}else{
					ans = tans2;
				}
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值