1001 Battle Over Cities - Hard Version (35 分)
解题思路:
枚举每个城市,破坏连着它的边,残留网络中跑克鲁斯卡尔最小生成树(并查集+边排序,排序在枚举城市循环外,一次排序即可),对于status=1的边是已经建成的,修改其cost=0即可。
坑点:
若破坏某个城市后网络不连通,则该城市的代价为最大(如果有多个这样的城市,则输出多个)
代码:
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define rd read()
#define pi 3.1415926535
using namespace std;
const ll mod = 998244353;
const int MAX1 = 100005;
const int MAX2 = 300005;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); }
#define int ll
struct ss
{
int s, e, status, cost;
}x[1000000];
bool cmp(ss a, ss b)
{
return a.status>b.status||(a.status==b.status&&a.cost < b.cost);
}
int fa[505];
ll value[505];
int find(int r)
{
return fa[r] == r ? r : fa[r] = find(fa[r]);
}
void join(int x, int y, int city, ss c)
{
int fx = find(x), fy = find(y);
if (fx != fy&&!c.status)value[city] += c.cost;
fa[fx] = fy;
}
signed main()
{
int n = rd, m = rd;
for (int i = 0; i < m; i++)
{
x[i].s = rd;
x[i].e = rd;
x[i].cost = rd;
x[i].status = rd;
}
sort(x, x + m, cmp);
for (int i = 1; i <= n; i++)
{
for (int i = 1; i <= n; i++)fa[i] = i;
for (int j = 0; j < m; j++)
{
if (x[j].s == i || x[j].e == i)continue;
join(x[j].s, x[j].e, i, x[j]);
}
int p = (i == 1 ? 2 : 1);
for (int k = 1; k <= n; k++)
{
if (find(p) != find(k) && k != i)
{
value[i] = 1e18;
}
}
}
ll ma = 0;
for (int i = 1; i <= n; i++)
{
ma = max(value[i], ma);
}
int k = 0;
if (ma == 0)
{
cout << 0;
return 0;
}
for (int i = 1; i <= n; i++)
{
if (ma == value[i]) {
if (k >= 1)cout << ' ';
cout << i;
k++;
}
}
return 0;
}