Bob’s Problem
题意:
一个有n个点的图,其中边分为白色和黑色,每个边都有边权,所选白边的数量的数量不能超过k,问现在选择一些边,使得所有点连通,问最大权值是多少?
题解:
我一开始以为是最大生成树,但是发现样例就不对,后来队友一说才反应过来,题目要求的是图连通,权值最大,那我们就要尽可能多选边,而非选n-1个边,因为黑边无限制,所有我们就全选黑边,然后对于白边,有k的数量限制,所有我们按照权值依次看加入白边是否可以使得图连通,如果k还有剩余再加入剩余白边
代码:
#include <bits/stdc++.h>using namespace std;
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 0x7fffffff;
const int Mod = 1e9 + 7;
const int maxn = 1e6 + 10;struct node {int from, to, w;bool operator<(const node &p) const { return w >= p.w; }
};
int n, m;
int f[maxn];
bitset<maxn> vis;
vector<node> res;int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }int main() {int t, k, u, v, w, cnt;ll ans;scanf("%d", &t);while (t--) {res.clear(), vis.reset();ans = cnt = 0;scanf("%d%d%d", &n, &m, &k);for (int i = 1; i <= n; i++) f[i] = i;for (int i = 1, x; i <= m; i++) {scanf("%d%d%d%d", &u, &v, &w, &x);if (x) {res.push_back({u, v, w});} else {ans += w;int fu = find(u), fv = find(v);if (fu != fv) {f[fu] = fv;++cnt;}}}sort(res.begin(), res.end());for (int i = 0; i < res.size() && k; i++) {u = res[i].from, v = res[i].to, w = res[i].w;int fu = find(u), fv = find(v);if (fu != fv) {f[fu] = fv;--k;ans += w;++cnt;vis[i] = 1;}}for (int i = 0; i < res.size() && k; i++) {if (!vis[i]) {ans += res[i].w;--k;}}for (int i = 1; i <= n; i++) find(i);bool ok = 1;int cur = f[1];for (int i = 2; i <= n; i++) {if (cur != f[i]) {ok = 0;break;}}if (!ok || cnt != n - 1) ans = -1;printf("%lld\n", ans);}return 0;
}