题意:给出两个不同方案,每个方案使得所有的城堡被连通(形成连通图),同时使边权之和尽量小,问第一个方案与第二个方案的大小关系。
解题思路:
因为m个桥能使n个城堡联通,而两个大爷的方案中至少存在一个桥不相同,那么我们判断这是一个求次小生成树的方法。
求次小生成树模板:
https://blog.csdn.net/alice_991/article/details/48225949
枚举+删边+再求MST复杂度有点高,看题解上面容易tle,所以采用上面链接里面的那种算法,为了复习并查集就用了Kruskal,复杂度为(N*2)
#include<cstdio>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 2e5+5;
struct node {
int u, v;
ll w;
bool operator < (node& rhs) {
return w < rhs.w;
}
}g[maxn];
int n, m, pre[2005];
int findset(int x) {
return x == pre[x] ? pre[x] : pre[x] = findset(pre[x]);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
pre[i] = i;
}
int x, y;
ll w;
for (int i = 0; i < m; i++) {
scanf("%d%d%lld", &x, &y, &w);
g[i].u = x;
g[i].v = y;
g[i].w = w;
}
int v1 = 0, v2 = 0, i, j;
sort(g, g + m);
for (i = 0; i < m; ) {
for (j = i; j < m && g[j].w == g[i].w; j++) {
int u = findset(g[j].u);
int v = findset(g[j].v);
if (u != v) v1++;
}
for (j = i; j < m && g[j].w == g[i].w; j++) {
int u = findset(g[j].u);
int v = findset(g[j].v);
if (u != v) {
v2++; pre[u] = v;
}
}
if (v2 == n - 1) break;
}
if (v2 < n - 1 || v1 > v2) printf("zin
");
else printf("ogisosetsuna
");
return 0;
}