三原色图
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 353 Accepted Submission(s): 134
Problem Description
度度熊有一张
n 个点 m 条边的无向图,所有点按照 1,2,⋯,n 标号,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。
现在度度熊想选出恰好 k 条边,满足只用这 k 条边之中的红色边和绿色边就能使 n 个点之间两两连通,或者只用这 k 条边之中的蓝色边和绿色边就能使 n个点之间两两连通,这里两个点连通是指从一个点出发沿着边可以走到另一个点。
对于每个 k=1,2,⋯,m,你都需要帮度度熊计算选出恰好 k 条满足条件的边的权值之和的最小值。
现在度度熊想选出恰好 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 分别表示红色、绿色和蓝色。
接下来依次描述 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求最小生成树。注意细节,当k>n-1时,边权和不再受颜色限制,只要是没用过的边都可以加进去
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define maxn 109
#define inf 0x3f3f3f3f
using namespace std;
int par[maxn], ranks[maxn];
void init_bcj(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
ranks[i] = 0;
}
}
int find_bcj(int x) {
if (par[x] == x) return x;
else {
return par[x] = find_bcj(par[x]);
}
}
bool unite(int x, int y) {
x = find_bcj(x);
y = find_bcj(y);
if (x == y) return 0;
if (ranks[x] < ranks[y]) {
par[x] = y;
}
else {
par[y] = x;
if (ranks[x] == ranks[y]) ranks[x]++;
}
return 1;
}
bool issame_bcj(int x, int y) {
return find_bcj(x) == find_bcj(y);
}
int t, n, m;
int ans[maxn];
struct node_edge
{
int u, v, w;
char c;
}e[maxn];
bool cmp(const node_edge &a, const node_edge &b) {
return a.w < b.w;
}
struct que
{
int a[maxn];
int count = 0;
};
void Kruskal(char fb) {
init_bcj(n);
que q;
int sum = 0,anst;
for (int i = 1; i <= m; i++) {
if (e[i].c != fb) {
if (!unite(e[i].u, e[i].v)) {
q.a[q.count] = e[i].w; q.count++;
}
else sum += e[i].w;
}
else {
q.a[q.count] = e[i].w; q.count++;
}
}
anst = m - q.count;
if (anst < n - 1) return;
ans[anst] = min(sum,ans[anst]);
for (int i = 0; i < q.count; i++) {
anst++;
sum += q.a[i];
ans[anst] = min(ans[anst], sum);
}
}
int main() {
fio;
cin >> t;
for (int i = 1; i <= t; i++) {
memset(ans, inf, sizeof ans);
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> e[i].u >> e[i].v >> e[i].w >> e[i].c;
}
sort(e + 1, e + 1 + m, cmp);
Kruskal('B');
Kruskal('R');
cout << "Case #"<<i<<":\n";
for (int i = 1; i <= m; i++) {
if (ans[i] == inf) cout << "-1" << endl;
else cout << ans[i] << endl;
}
}
return 0;
}