三原色图
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 524 Accepted Submission(s): 177
Problem Description
度度熊有一张
n
个点
m
条边的无向图,所有点按照
1,2,⋯,n
标号,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。
现在度度熊想选出恰好
k
条边,满足只用这
k
条边之中的红色边和绿色边就能使
n
个点之间两两连通,或者只用这
k
条边之中的蓝色边和绿色边就能使
n
个点之间两两连通,这里两个点连通是指从一个点出发沿着边可以走到另一个点。
对于每个
k=1,2,⋯,m
,你都需要帮度度熊计算选出恰好
k
条满足条件的边的权值之和的最小值。
Input
第一行包含一个正整数
T
,表示有
T
组测试数据。
接下来依次描述
T
组测试数据。对于每组测试数据:
第一行包含两个整数
n
和
m
,表示图的点数和边数。
接下来
m
行,每行包含三个整数
a,b,w
和一个字符
c
,表示有一条连接点
a
与点
b
的权值为
w
、颜色为
c
的无向边。
保证
1≤T≤100
,
1≤n,m≤100
,
1≤a,b≤n
,
1≤w≤1000
,
c∈{R,G,B}
,这里
R,G,B
分别表示红色、绿色和蓝色。
Output
对于每组测试数据,先输出一行信息 “Case #x:”(不含引号),其中 x 表示这是第
x
组测试数据,接下来
m
行,每行包含一个整数,第
i
行的整数表示选出恰好
i
条满足条件的边的权值之和的最小值,如果不存在合法方案,输出
−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
解题思路:这个题本身就是一个考察kruskal算法的一个题,首先要了解kruskal算法,这种算法,网上有很多模板,我也写过类似文章,不再多说,这个题的关键就是不是建立两个并查集,而是一个并查集进行两遍。还有注意始终不符合条件的情况
#include<bits/stdc++.h>
#define ull unsigned long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=210;
int par[maxn];//并查集的数组
priority_queue<int,vector<int>,greater<int> >q;
int c[maxn];//记录结果
struct node
{
int u,v,w;
int col;
bool operator<(node a)const{
return w<a.w;
}
}a[maxn];
void init(int n)
{
for(int i=0;i<=n;i++)
{
par[i]=i;
}
}
int find(int x){
int root=x;
while(root!=par[root]) root=par[root];
while(x!=root){
int t=par[x];
par[x]=root;
x=t;
}
return root;
}
void un(int x,int y)
{
x=find(x);
y=find(y);
par[x]=y;
}
void kruskal(int n,int m,int ch)
{
int ng=0,res=0;//res是最优解,ng是建立的树的边(树的边永远比点 少一);
sort(a,a+m);
while(!q.empty())
q.pop();
for(int i=0;i<m;i++)
if(a[i].col!=ch&&ng<n-1){
if(find(a[i].u)!=find(a[i].v)){
un(a[i].u,a[i].v);
res+=a[i].w;
ng++;
}
else q.push(a[i].w);
}
else
q.push(a[i].w);
if(ng<n-1)
{
res=-1;
return;
}
int k=n-1;
//更新结果的数据
if(c[k]==-1)
c[k]=res;
else
c[k]=min(c[k],res);
while(!q.empty())
{
res+=q.top();
q.pop();
k++;
if(c[k]==-1)
c[k]=res;
else
c[k]=min(c[k],res);
}
}
int main()
{
int n,m,s,T,cas=1;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
init(n);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
char ch;
cin>>ch;
if(ch=='B')a[i].col=0;
else if(ch=='R')a[i].col=1;
else if(ch=='G')a[i].col=2;
}
memset(c,-1,sizeof(c));
kruskal(n,m,0);
init(n);
kruskal(n,m,1);
printf("Case #%d:\n",cas++);
for(int i=1;i<=m;i++)
printf("%d\n",c[i]);
}
return 0;
}