【双连通分量】 HDOJ 2242 考研路茫茫——空调教室

这道题只要求一下双连通分量就好了。。求双连通分量可以先求出桥。。。原图删了桥以后形成的各个连通子图就是双连通分量。。。然后缩点,缩点以后就是一棵树,最后在树上进行树形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;
}


你可能感兴趣的:(HDU)