大意:给定一个无向图,问是否存在一条边使得删去该边后,使得该边左、右的双联通分量的权值的差值尽量小。
思路:求得双连通分量后,把原图缩成了一棵树,然后再树上做DP即可,求ans = min(ans, (sum-val*2)); 其中val为左右子树的权值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <algorithm> #include <map> using namespace std; const int maxn = 10010; const int maxm = 200010*2; const int INF = 0x3f3f3f3f; struct Edge { int u, v, w; int next; int id; }edge[maxm], edge2[maxm]; int first[maxn], stack[maxn], ins[maxn], dfn[maxn], low[maxn]; int first2[maxn]; int belong[maxn]; int ind[maxn], outd[maxn]; int cost[maxn]; int w[maxn]; int n, m; int cnt, cnt2; int scnt, top, tot; void init() { cnt = cnt2 = 0; scnt = top = tot = 0; memset(first, -1, sizeof(first)); memset(first2, -1, sizeof(first2)); memset(dfn, 0, sizeof(dfn)); memset(ins, 0, sizeof(ins)); memset(ind, 0, sizeof(ind)); memset(cost, 0, sizeof(cost)); } void read_graph(int u, int v) { edge[cnt].u = u, edge[cnt].v = v; edge[cnt].next = first[u], first[u] = cnt++; } void read_graph2(int u, int v, int w) { edge2[cnt2].u = u, edge2[cnt2].v = v, edge2[cnt2].w = w; edge2[cnt2].next = first2[u], first2[u] = cnt2++; } vector<Edge> bridge; void dfs(int u, int fa) { int v; low[u] = dfn[u] = ++tot; stack[top++] = u; ins[u] = 1; bool repeat = 0; for(int e = first[u]; e != -1; e = edge[e].next) { v = edge[e].v; if(v == fa && !repeat) { repeat = 1; continue; } if(!dfn[v]) { dfs(v, u); low[u] = min(low[u], low[v]); if(dfn[u] < low[v]) { bridge.push_back(edge[e]); //保存割边 } } else if(ins[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { scnt++; do { v = stack[--top]; belong[v] = scnt; ins[v] = 0; cost[scnt] += w[v]; } while(u != v); } } void Tarjan() { for(int v = 1; v <= n; v++) if(!dfn[v]) dfs(v, -1); } int sum; void read_case() { init(); sum = 0; for(int i = 1; i <= n; i++) { scanf("%d", &w[i]); sum += w[i]; } while(m--) { int u, v; scanf("%d%d", &u, &v); u++; v++; read_graph(u, v), read_graph(v, u); } } void build() { Tarjan(); for(int u = 1; u <= n; u++) { for(int e = first[u]; e != -1; e = edge[e].next) { int v = edge[e].v; if(belong[u] != belong[v]) { read_graph2(belong[u], belong[v], cost[belong[v]]); } } } } int d[maxn]; bool vis[maxn]; int dp(int u, int fa, int &ans) { int val = cost[u]; for(int e = first2[u]; e != -1; e = edge2[e].next) { int v = edge2[e].v; if(v == fa) continue; //重要 val += dp(v, u, ans); } ans = min(ans, abs(sum-val*2)); return val; } void solve() { read_case(); build(); if(scnt == 1) { printf("impossible\n"); return; } int ans = INF; dp(1, -1, ans); printf("%d\n", ans); } int main() { while(~scanf("%d%d", &n, &m)) { solve(); } return 0; }