题干:
度度熊有一张 nn 个点 mm 条边的无向图,所有点按照 1,2,⋯,n1,2,⋯,n 标号,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。
现在度度熊想选出恰好 kk 条边,满足只用这 k 条边之中的红色边和绿色边就能使 n 个点之间两两连通,或者只用这 kk 条边之中的蓝色边和绿色边就能使 nn 个点之间两两连通,这里两个点连通是指从一个点出发沿着边可以走到另一个点。
对于每个 k=1,2,⋯,mk=1,2,⋯,m,你都需要帮度度熊计算选出恰好 kk 条满足条件的边的权值之和的最小值。
Input
第一行包含一个正整数 TT,表示有 TT 组测试数据。
接下来依次描述 TT 组测试数据。对于每组测试数据:
第一行包含两个整数 nn 和 mm,表示图的点数和边数。
接下来 mm 行,每行包含三个整数 a,b,wa,b,w 和一个字符 cc,表示有一条连接点 aa 与点 bb 的权值为 ww、颜色为 cc 的无向边。
保证 1≤T≤1001≤T≤100,1≤n,m≤1001≤n,m≤100,1≤a,b≤n1≤a,b≤n,1≤w≤10001≤w≤1000,c∈{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
解题报告:
刚开始读错题了很尴尬、、题面说的是 用k条红色边绿色边 或者 用k条蓝色边绿色边,我理解成了并且,也就是这k条边必须仅用红绿可以构成生成树,并且仅用蓝绿也可以构成生成树了、、、如果是那样的话就比较难考虑了。。不过这个题还好,直接用红绿求一个,用蓝绿求一个,这样分成两个独立的问题。对于每个问题,先构成MST,然后直接贪心加边就行了。
AC代码:
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int n,m,flag[MAX],f[MAX],ans[MAX];
struct Edge {
int u,v,w;
int col;//0绿 1红 2蓝
Edge(int u=0,int v=0,int w=0,int col=0):u(u),v(v),w(w),col(col) {}
friend bool operator < (Edge a,Edge b) {
return a.w < b.w;
}
} e[MAX];
int getf(int v) {
return f[v] == v ? v : f[v] = getf(f[v]);
}
void init() {
for(int i = 1; i<=n; i++) f[i] = i;
for(int i = 1; i<=m; i++) flag[i] = 0;
}
void Klu(int col) {
init();
int res = 0,cnt = 0;
for(int u,v,i = 1; i<=m; i++) {
u = getf(e[i].u); v = getf(e[i].v);
if(u == v || e[i].col == col) continue;
f[v] = u;
cnt++;
res += e[i].w;
flag[i] = 1;
}
if(cnt < n-1) return;
int top = n-1;
ans[top] = min(ans[top],res);
for(int i = 1; i<=m; i++) {
if(flag[i] == 1) continue;
res += e[i].w;
top++;
ans[top] = min(ans[top],res);
}
}
int main() {
int t,iCase=0;
char s[5];
cin>>t;
while(t--) {
scanf("%d%d",&n,&m);
for(int i = 1; i<=m; i++) ans[i] = INF;
for(int a,b,c,i = 1; i<=m; i++) {
scanf("%d%d%d%s",&a,&b,&c,s);
e[i] = Edge(a,b,c,0);
if(s[0] == 'R') e[i].col = 1;
if(s[0] == 'B') e[i].col = 2;
}
sort(e+1,e+m+1);
Klu(1);
Klu(2);
printf("Case #%d:\n",++iCase);
for(int i = 1; i<=m; i++) {
if(ans[i] == INF) puts("-1");
else printf("%d\n",ans[i]);
}
}
return 0 ;
}
/*
1
3 6
1 2 100 G
2 3 100 G
1 2 1 B
2 3 10 B
1 2 2 R
2 3 20 R
Case #1:
-1
11
13
33
133
233
*/
读错题太可怕了,直接由一个水题变成一个不可做题、、