cpp
复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5+10;
int n, m;
int a[N], p[N];
ll ans = 1e18;
ll s[3];
bool st;
struct edge
{
int a, b;
} e[N];
void init()
{
for(int i = 1; i <= n; i++)
p[i] = i;
}
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void check()
{
int cnt = 0;
int fir = find(1);
for(int i = 1; i <= n; i++)
{
if(p[i] == i) cnt++;
if(p[i] == fir) s[1] += a[i];
else s[2] += a[i];
}
if(cnt == 2) st = true, ans = min(ans, abs(s[2] - s[1]));
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", a+i);
for(int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
e[i] = {a, b};
}
for(int i = 1; i <= m; i++)
{
init(); s[1] = s[2] = 0;
for(int j = 1; j <= m; j++)
{
if(i == j) continue;
int a = e[j].a, b = e[j].b;
int pa = find(a), pb = find(b);
if(pa != pb) p[pa] = pb;
}
check();
}
if(st) printf("%lld", ans);
else puts("-1");
}
cpp
复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5+10;
const int M = 4e5+10;
int n, m;
int a[N]; //权重
ll f[N]; //子树权重和
int h[N], e[M], ne[M], idx; //链式前向星
ll sum, ans = 1e18; //权重和 答案
int dfn[N], low[N], tot; //时间戳 追溯值 分配器
bool flag; //割边存在性
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void tarjan(int u, int ine)
{
dfn[u] = ++tot, low[u] = tot;
f[u] = a[u];
for(int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if(!dfn[j])
{
tarjan(j, i);
f[u] += f[j];
low[u] = min(low[u], low[j]);
if(low[j] > dfn[u]) //这里放在向下的部分,因为dfn[u]是固定的,向上的部分只会影响到low[u]
{
ans = min(ans, abs(sum - 2 * f[j]));
flag = true;
}
}
else if(i != (ine ^ 1))
low[u] = min(low[u], dfn[j]);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
scanf("%d", a+i);
sum += a[i];
}
memset(h, -1, sizeof h);
for(int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b); add(b, a);
}
tarjan(1, -1); //调用时,第二个参数随便给
if(f[1] != sum) ans = sum - 2 * f[1]; //不是连通图,直接求差(本题默认所给图最多两个连通分量)
else
if(!flag) ans = -1; //是连通图,无割边
printf("%lld", ans);
}