传送门:题目
题意:
给定一个图,边是无向边,然后每条边有一个权值和一种颜色,求用特定两种颜色的边组成强连通图,然后问讯 k∈[1,m] k ∈ [ 1 , m ] 边的加权和的最小值。
题解:
题目很好理解,我们只需要分别建两个图,然后分别找两个最小生成树就行了,然后把不是属于最小生成树的边从小到大排个序,最后遍历一下,加到最小生成树的权值和上面去。第一开始套个模板就写完了,但是一直WA,最后发现,忘记当无法生成最小生成树的时候,就不要更新答案了,直接return就行了,这个BUG改了1天。。。顺便更新了一下Kruskal的模板
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;
const int maxv = 110;
const int maxe = 110;
int ret[maxe];
vector<int> p;
/*******************Kruskal+并查集优化+递归写法*****************************/
//Kruskal处理稀疏图效果优于Prim
//注意:递归可能爆栈
int pre[maxv], cnt;
struct Edge {
int from, to, val;
bool operator<(const Edge& rhs)const {
return val < rhs.val;
}
} edge[maxe];
void init() {
cnt = 0;
memset(pre, -1, sizeof pre);
p.clear();
}
void addedge(int from, int to, int val) {
edge[cnt].from = from;
edge[cnt].to = to;
edge[cnt++].val = val;
}
int Find(int x) { //并查集
return pre[x] == -1 ? x : pre[x] = Find(pre[x]);
}
void Kruskal(int n, int m) { //n代表图种总共的顶点数
sort(edge, edge + cnt);
int ecnt = 0, ans = 0;
for (int i = 0; i < cnt; i++) {
if (ecnt < n - 1) {
int f1 = Find(edge[i].from);
int f2 = Find(edge[i].to);
if (f1 != f2) {
ans += edge[i].val;
pre[f1] = f2;
ecnt++;
}
else
p.emplace_back(edge[i].val);
}
else
p.emplace_back(edge[i].val);
}
sort(p.begin(), p.end());
if (ecnt < n - 1)
return;
if (ret[ecnt] == -1)
ret[ecnt] = ans;
else
ret[ecnt] = min(ans, ret[ecnt]);
int sum = ans;
for (auto x : p) {
sum += x;
ecnt++;
if (ret[ecnt] == -1)
ret[ecnt] = sum;
else
ret[ecnt] = min(ret[ecnt], sum);
}
}
/*******************Kruskal+并查集优化+递归写法*****************************/
int main(void) {
int T, kase = 1;
cin >> T;
while (T--) {
memset(ret, -1, sizeof ret);
int n, m, t1[maxe], t2[maxe], t3[maxe];
char ch[maxe];
cin >> n >> m;
for (int i = 0; i < m; i++)
cin >> t1[i] >> t2[i] >> t3[i] >> ch[i];
init();
for (int i = 0; i < m; i++) {
if (ch[i] != 'B')
addedge(t1[i], t2[i], t3[i]);
else
p.emplace_back(t3[i]);
}
Kruskal(n, m);
init();
for (int i = 0; i < m; i++) {
if (ch[i] != 'R')
addedge(t1[i], t2[i], t3[i]);
else
p.emplace_back(t3[i]);
}
Kruskal(n, m);
cout << "Case #" << kase++ << ":" << endl;
for (int i = 1; i <= m; i++)
cout << ret[i] << endl;
}
return 0;
}