思路就是求边双连通分量,然后缩点,再用树形DP搞一下。
代码和求强连通很类似,有点神奇,=_=,慢慢消化吧
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <stack> 6 using namespace std; 7 8 const int maxn = 10000 + 10; 9 const int maxm = 20000 + 10; 10 11 int n, m; 12 int a[maxn]; 13 14 struct Edge 15 { 16 int v, nxt; 17 }edges[maxm * 2]; 18 int ecnt; 19 int head[maxn]; 20 21 bool vis[maxn]; 22 23 void AddEdge(int u, int v) 24 { 25 edges[ecnt].v = v; 26 edges[ecnt].nxt = head[u]; 27 head[u] = ecnt++; 28 } 29 30 stack<int> S; 31 int dfs_clock, scc_cnt; 32 int low[maxn], pre[maxn], sccno[maxn], w[maxn]; 33 34 void dfs(int u, int fa) 35 { 36 low[u] = pre[u] = ++dfs_clock; 37 S.push(u); 38 39 for(int i = head[u]; ~i; i = edges[i].nxt) 40 { 41 if(i == (fa ^ 1)) continue; 42 int v = edges[i].v; 43 if(!pre[v]) 44 { 45 dfs(v, i); 46 low[u] = min(low[u], low[v]); 47 } 48 else if(!sccno[v]) low[u] = min(low[u], pre[v]); 49 } 50 51 if(pre[u] == low[u]) 52 { 53 scc_cnt++; 54 for(;;) 55 { 56 int x = S.top(); S.pop(); 57 sccno[x] = scc_cnt; 58 w[scc_cnt] += a[x]; 59 if(x == u) break; 60 } 61 } 62 } 63 64 void find_scc() 65 { 66 scc_cnt = dfs_clock = 0; 67 memset(w, 0, sizeof(w)); 68 memset(pre, 0, sizeof(pre)); 69 memset(sccno, 0, sizeof(sccno)); 70 for(int i = 0; i < n; i++) if(!pre[i]) dfs(i, -1); 71 } 72 73 vector<int> G[maxn]; 74 75 void dfs2(int u) 76 { 77 vis[u] = true; 78 for(int i = 0; i < G[u].size(); i++) 79 { 80 int v = G[u][i]; 81 if(vis[v]) continue; 82 dfs2(v); 83 w[u] += w[v]; 84 } 85 } 86 87 int main() 88 { 89 while(scanf("%d%d", &n, &m) == 2 && n) 90 { 91 int sum = 0; 92 for(int i = 0; i < n; i++) { scanf("%d", a + i); sum += a[i]; } 93 94 memset(head, -1, sizeof(head)); 95 ecnt = 0; 96 97 while(m--) 98 { 99 int u, v; scanf("%d%d", &u, &v); 100 AddEdge(u, v); AddEdge(v, u); 101 } 102 103 find_scc(); 104 105 if(scc_cnt == 1) { puts("impossible"); continue; } 106 107 for(int i = 1; i <= scc_cnt; i++) G[i].clear(); 108 for(int u = 0; u < n; u++) 109 for(int i = head[u]; ~i; i = edges[i].nxt) 110 { 111 int v = edges[i].v; 112 if(sccno[u] != sccno[v]) G[sccno[u]].push_back(sccno[v]); 113 } 114 115 memset(vis, false, sizeof(vis)); 116 dfs2(1); 117 118 int ans = 1000000000; 119 for(int i = 1; i <= scc_cnt; i++) ans = min(ans, abs(sum - w[i] * 2)); 120 printf("%d\n", ans); 121 } 122 123 return 0; 124 }
代码君
时间: 2024-10-07 11:57:57