标签:
4 3 1 1 1 1 0 1 1 2 2 3 4 3 1 2 3 5 0 1 1 2 2 3
0 1
#include <cstdio> #include <cstring> #include <stack> #include <queue> #include <vector> #include <cmath> #include <cstdlib> #include <algorithm> #define MAXN 10000+10 #define MAXM 40000+100 #define INF 10000000 using namespace std; struct Edge { int from, to, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int man[MAXN]; int low[MAXN], dfn[MAXN]; int dfs_clock; int ebcno[MAXN], ebc_cnt; stack<int> S; bool Instack[MAXN]; vector<int> ebc[MAXN]; int N, M;//N个教室 M个管道 int total;//记录所有教室的总人数 void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v) { Edge E = {u, v, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } void getMap() { int a, b; while(M--) { scanf("%d%d", &a, &b); addEdge(a, b); addEdge(b, a); } } void tarjan(int u, int fa) { int v, flag = 0; low[u] = dfn[u] = ++dfs_clock; S.push(u); Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(v == fa && !flag) { flag = 1; continue; } if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { ebc_cnt++; ebc[ebc_cnt].clear(); for(;;) { v = S.top(); S.pop(); Instack[v] = false; ebcno[v] = ebc_cnt; ebc[ebc_cnt].push_back(v); if(v == u) break; } } } void find_cut(int l, int r) { dfs_clock = ebc_cnt = 0; memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(ebcno, 0, sizeof(ebcno)); memset(Instack, false, sizeof(Instack)); for(int i = l; i <= r; i++) if(!dfn[i]) tarjan(i, -1); } int ebc_man[MAXN];//记录每个EBC的人数 vector<int> G[MAXN]; void suodian() { for(int i = 1; i <= ebc_cnt; i++) { G[i].clear(); int sum = 0; for(int j = 0; j < ebc[i].size(); j++) sum += man[ebc[i][j]]; ebc_man[i] = sum; } for(int i = 0; i < edgenum; i+=2)//建图 一开始没加 i+=2 无语。。。 { int u = ebcno[edge[i].from]; int v = ebcno[edge[i].to]; if(u != v) G[u].push_back(v), G[v].push_back(u); } } int ans;//最小差值 int num[MAXN];//统计子节点 权值之和 void DFS(int u, int fa)//求解 最小差值 { num[u] = ebc_man[u]; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v == fa) continue; DFS(v, u); num[u] += num[v]; } ans = min(ans, abs(total - 2 * num[u]));//更新 } void solve() { find_cut(0, N-1);//找EBC if(ebc_cnt == 1)//只有一个EBC { printf("impossible\n"); return ; } suodian();//缩点 ans = INF; DFS(1, -1);//遍历整棵树 printf("%d\n", ans); } int main() { while(scanf("%d%d", &N, &M) != EOF) { total = 0; for(int i = 0; i < N; i++) scanf("%d", &man[i]), total += man[i];//统计总人数 init(); getMap(); solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdoj 2242 考研路茫茫——空调教室 【无向图求边双联通 缩点 + 树形dp】
标签:
原文地址:http://blog.csdn.net/chenzhenyu123456/article/details/47629337