三原色图
度度熊有一张 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
AC代码
//#include<bits/stdc++.h>
#define _CRT_SBCURE_NO_DEPRECATE
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
//#define UP(i,x,y) for(int i=x;i<=y;i++)
//#define DOWN(i,x,y) for(int i=x;i>=y;i--)
#define sdddd(x,y,z,k) scanf("%d%d%d%d", &x, &y, &z, &k)
#define sddd(x,y,z) scanf("%d%d%d", &x, &y, &z)
#define sdd(x,y) scanf("%d%d", &x, &y)
#define sd(x) scanf("%d", &x)
#define mp make_pair
#define pb push_back
#define lson k<<1
#define rson k<<1|1
#define mid (l+r)/2
#define ms(x, y) memset(x, y, sizeof x)
using namespace std;
typedef long long ll;
//typedef unsigned long long ull;
#define MOD 1000000007
const int maxn = 105;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int n, m, s, t;
int len;
struct road
{
int u, v;
char col[3];
bool vis2;
bool vis1;
int cost;
};
road G[maxn<<1];
int par[maxn];
void init()
{
for(int i = 1; i <= n; i++) par[i] = i;
}
int Find(int x)
{
return par[x]==x ? x : par[x] = Find(par[x]);
}
bool same(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy)return true;
else return false;
}
void unite(int x, int y)
{
int fx = Find(x), fy = Find(y);
if(fx == fy)return;
else{
par[fx] = fy;
}
}
bool cmp(road a, road b)
{
return a.cost < b.cost;
}
int resa = 0;
int resb = 0;
void kruskal()
{
init();
sort(G, G+m, cmp);
int cnt = 1;
for(int i = 0; i < m; i++)
{
if(G[i].col[0] != 'B' && !same(G[i].u, G[i].v))
{
resa += G[i].cost;
cnt++;
G[i].vis1 = true;
unite(G[i].u, G[i].v);
}
}
if(cnt == n){}
else resa = INF;
init();
cnt = 1;
for(int i = 0; i < m; i++)
{
if(G[i].col[0] != 'R' && !same(G[i].u, G[i].v))
{
resb += G[i].cost;
cnt++;
G[i].vis2 = true;
unite(G[i].u, G[i].v);
}
}
if(cnt == n){}
else resb = INF;
}
int main()
{
//freopen("out.txt", "w", stdout);
sd(t);int a = 1;
while(t--)
{
sdd(n,m);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d%s", &G[i].u, &G[i].v, &G[i].cost, G[i].col);
G[i].vis1 = false; G[i].vis2 = false;
}
resa = 0;resb = 0;
kruskal();
if(resa == INF && resb == INF)
{
printf("Case #%d:\n", a++);
for(int i = 0; i < m; i++)
{
printf("-1\n");
}
continue;
}
printf("Case #%d:\n", a++);
for(int i = 1; i < n-1; i++)
{
printf("-1\n");
}
if(resa<resb)
{
printf("%d\n", resa);
}
else
{
printf("%d\n", resb);
}
for(int i = n; i <=m; i++)
{
bool fa = false;
bool fb = false;
if(resa<INF)
fa = true;
if(resb<INF)
fb = true;
for(int j = 0; j <= m; j++)
{
if(fa&&!G[j].vis1)
{
resa += G[j].cost;
fa = false;
G[j].vis1 = true;
}
if(fb&&!G[j].vis2)
{
resb += G[j].cost;
fb = false;
G[j].vis2 = true;
}
if(!fa&&!fb) break;
}
if(resa<resb)
{
printf("%d\n", resa);
}
else
{
printf("%d\n", resb);
}
}
}
return 0;
}