您的位置:首页 > 其它

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

2014-07-28 20:11 411 查看
这道题只要求一下双连通分量就好了。。求双连通分量可以先求出桥。。。原图删了桥以后形成的各个连通子图就是双连通分量。。。然后缩点,缩点以后就是一棵树,最后在树上进行树形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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: