 /**//*
題意:給出一些點(diǎn),有值,給出一些邊,然后求去掉一條邊后將分成連通的兩部分,且兩部分的差值最小
先將雙連通分量縮點(diǎn),成為一棵樹,樹邊即橋,然后再遞歸一下就行
注意,這里的重邊當(dāng)成兩條路!!!
如 1-0 1-0 則他們屬雙連通


與poj 3140類似,不過那道簡單點(diǎn),給出的是樹,就注意下__int64
還有,如果stack overflow的話,試試在代碼最前面加
#pragma comment(linker, "/STACK:102400000,102400000")
還是有問題的話,那就是代碼問題了
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int MAXN=10010;
const int INF=2000000000;

 struct Node {
int v,next;
}nodes[MAXN*2];

int G[MAXN],low[MAXN],level[MAXN];
int color[MAXN];
int sum[MAXN],A[MAXN];
int ans,N;
int vi[MAXN];
vector<pair<int,int> >Bridge;//存橋,方便重新建圖
int alloc,n,m,ID;

 void add(int a,int b) {
nodes[alloc].v=b;nodes[alloc].next=G[a];
G[a]=alloc++;
}

 void dfs(int u,int p,int dep) {
vi[u]=1;
level[u]=low[u]=dep;
bool flag=true;//因?yàn)榭赡苡兄剡卾->u,但第一條不算有效的(屬u->v),所以標(biāo)記一下flag即可,很重要!
 for(int son=G[u];son!=-1;son=nodes[son].next) {
int v=nodes[son].v;
 if(v==p&&flag) {
flag=false;
continue;
}
if(vi[v]==1)low[u]=min(low[u],level[v]);
 else if(vi[v]==0) {
dfs(v,u,dep+1);
low[u]=min(low[u],low[v]);
if(low[v]>level[u])
Bridge.push_back(make_pair(u,v));
}
}
vi[u]=2;
}

 void setColor(int u,int p) {
sum[color[u]]+=A[u];
 for(int son=G[u];son!=-1;son=nodes[son].next) {
int v=nodes[son].v;
if(color[v])continue;
if(low[v]>level[u])color[v]=++ID;
else color[v]=color[u];
setColor(v,u);
}
}

 int DP(int u,int p) {
A[u]=sum[u];
 for(int son=G[u];son!=-1;son=nodes[son].next) {
int v=nodes[son].v;
if(v==p)continue;
int tmp=DP(v,u);
A[u]+=tmp;
ans=min(ans,abs(N-tmp*2));
}
return A[u];
}

 int main() {
int a,b,t=1;
 while(~scanf("%d%d",&n,&m)) {
N=0;
 for(int i=0;i<n;i++) {
scanf("%d",&A[i]);
N+=A[i];
}
alloc=0;
memset(G,-1,sizeof(int)*n);
 for(int i=1;i<=m;i++) {
scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
Bridge.clear();
memset(vi,0,sizeof(int)*n);
dfs(0,0,0);

memset(color,0,sizeof(int)*n);
memset(sum+1,0,sizeof(int)*n);
color[0]=ID=1;
setColor(0,0);
//build again
memset(G+1,-1,sizeof(int)*ID);
alloc=0;
 for(int i=0;i<Bridge.size();i++) {
int u=Bridge[i].first,v=Bridge[i].second;
//是add color[u],不是u
add(color[u],color[v]);add(color[v],color[u]);
}
if(ID==1)puts("impossible");//只有一個(gè)點(diǎn)時(shí)就是impossible
 else {
ans=INF;
DP(1,1);//這里是1開始,前面是0開始
printf("%d\n",ans);
}
}
return 0;
}

|