HDU6349-三原色图 Kruskal求最小生成树
三原色图
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; }