这道题就是模板的题加上一道很水的树形dp
感觉就先用
1,双连通缩点,如果只存在一个双连通分量,那么肯定是删除任何一个点,这个图还是连通的,
2,利用树形dp把缩点后连成一个图,然后用树形dp的一个dfs就算出答案了
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
#define N 10010
vector <int > mp[N];
vector <int > mp2[N];
stack <int > g;
int id[N];
int val[N];
int number,cnt;
int indexx;
int dfn[N],low[N];
int ans,sum;
int num[N];
int vis[N];
int n,m;
int abs(int x){
return (x>0)?x:-x;
}
void doubletarjian(int u,int fa){
int j,v,flag;
dfn[u]=low[u]=++indexx;
vis[u]=1;
g.push(u);
flag=0;
for(int i=0;i<mp[u].size();i++){
v = mp[u][i];
if(v==fa&&!flag){ flag=1;continue;}
if(!vis[v]) doubletarjian(v,u);
low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u]){
number++;
while(!g.empty()){
v = g.top();
g.pop();
id[v]=number;
num[number]+=val[v];
if(u==v) break;
}
}
}
void init(){
while(!g.empty()){
g.pop();
}
for(int i=0;i<=n;i++){
mp[i].clear();
mp2[i].clear();
}
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
number=0;
indexx=0;
sum=0;
memset(val,0,sizeof(val));
memset(vis,0,sizeof(vis));
memset(id,0,sizeof(id));
memset(num,0,sizeof(num));
}
int dfs(int u,int fa){
//printf("%d->%d ans==%d\n",fa,u,ans);
int ret;
ret=num[u];
for(int i=0;i<mp2[u].size();i++){
int v= mp2[u][i];
if(v==fa) continue;
ret+=dfs(v,u);
}
ans=min(ans,abs(sum-2*ret));
return ret;
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
for(int i=0;i<n;i++){
scanf("%d",&val[i]);
sum+=val[i];
}
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
mp[a].push_back(b);
mp[b].push_back(a);
}
doubletarjian(0,0);
// printf("test...\n");
// printf("sum==%d\n",sum);
// for(int i=1;i<=number;i++)
// printf("%d->>>%d\n",i,num[i]);
if(number==1){
printf("impossible\n");
continue;
}
for(int i=0;i<n;i++)
for(int j=0;j<mp[i].size();j++){
if(id[mp[i][j]]!=id[i])
mp2[id[i]].push_back(id[mp[i][j]]);
//mp2[id[mp[i][j]]].push_back(id[i]);
}
ans=0x7f7f7f7f;
dfs(1,0);
printf("%d\n",ans);
}
}原文地址:http://blog.csdn.net/u013076044/article/details/41833175