这道题只要求一下双连通分量就好了。。求双连通分量可以先求出桥。。。原图删了桥以后形成的各个连通子图就是双连通分量。。。然后缩点,缩点以后就是一棵树,最后在树上进行树形DP就好了。。。有关的学习资料Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)
#include <iostream> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <algorithm> #include <cstring> #include <climits> #include <cstdlib> #include <cmath> #include <time.h> #define maxn 10005 #define maxm 40005 #define eps 1e-10 #define mod 1000000009 #define INF 99999999 #define lowbit(x) (x&(-x)) #define pii pair<LL, LL> #define mp(a, b) make_pair(a, b) //#define lson o<<1, L, mid //#define rson o<<1 | 1, mid+1, R typedef long long LL; using namespace std; int H[maxn], NEXT[maxm], V[maxm], OK[maxm]; int h[maxn], next[maxm], v[maxm], ok[maxm]; int f[maxm], dfn[maxn], low[maxn], num[maxn]; int vis[maxn], id[maxn], w[maxn], W[maxn]; int top, dcc_cnt, n, m, ans, tot; void init(void) { top = dcc_cnt = tot = 0; memset(h, -1, sizeof h); memset(H, -1, sizeof H); memset(f, -1, sizeof f); memset(w, 0, sizeof w); memset(W, 0, sizeof W); memset(ok, 0, sizeof ok); memset(OK, 0, sizeof OK); memset(dfn, 0, sizeof dfn); } void read(void) { int a, b, cnt = 0; for(int i = 1; i <= n; i++) scanf("%d", &num[i]), tot += num[i]; while(m--) { scanf("%d%d", &a, &b); a++, b++; NEXT[cnt] = H[a], H[a] = cnt, V[cnt] = b, cnt++; NEXT[cnt] = H[b], H[b] = cnt, V[cnt] = a, cnt++; } } void init_dfs(int u) { if(vis[u]) return; vis[u] = 1, ans++; for(int e = H[u]; ~e; e = NEXT[e]) init_dfs(V[e]); } void tarjan(int u) { dfn[u] = low[u] = ++top; for(int e = H[u]; ~e; e = NEXT[e]) { if(!dfn[V[e]]) { f[V[e]] = e; tarjan(V[e]); low[u] = min(low[u], low[V[e]]); } else if(f[u] != (e^1)) low[u] = min(low[u], dfn[V[e]]); } if(f[u] != -1 && low[u] == dfn[u]) OK[f[u]] = 1, OK[f[u]^1] = 1; } void dfs(int u) { if(vis[u]) return; vis[u] = 1, id[u] = dcc_cnt, w[dcc_cnt] += num[u]; for(int e = H[u]; ~e; e = NEXT[e]) if(!OK[e]) dfs(V[e]); } void narrow(void) { int cnt = 0; for(int i = 1; i <= n; i++) for(int e = H[i]; ~e; e = NEXT[e]) next[cnt] = h[id[i]], h[id[i]] = cnt, v[cnt] = id[V[e]], ok[cnt] = OK[e], cnt++; } void debug(void) { printf("AAAA %d\n", dcc_cnt); for(int i = 1; i <= dcc_cnt; i++) printf("%d\n", W[i]); } void DFS(int u) { for(int e = h[u]; ~e; e = next[e]) if(v[e] != u && !vis[v[e]] && ok[e]) vis[v[e]] = 1, DFS(v[e]), W[u] += W[v[e]]; W[u] += w[u]; } void dp_dfs(int u) { for(int e = h[u]; ~e; e = next[e]) if(v[e] != u && !vis[v[e]] && ok[e]) vis[v[e]] = 1, dp_dfs(v[e]), ans = min(ans, abs(tot-W[v[e]]*2)); } void work(void) { memset(vis, 0, sizeof vis); ans = 0; init_dfs(1); if(ans != n) { printf("impossible\n"); return; } for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); memset(vis, 0, sizeof vis); for(int i = 1; i <= n; i++) if(!vis[i]) ++dcc_cnt, dfs(i); if(dcc_cnt == 1) { printf("impossible\n"); return; } narrow(); memset(vis, 0, sizeof vis); vis[1] = 1, DFS(1); ans = INF; memset(vis, 0, sizeof vis); vis[1] = 1, dp_dfs(1); printf("%d\n", ans); } int main(void) { while(scanf("%d%d", &n, &m)!=EOF) { init(); read(); work(); } return 0; }