这道题就是模板的题加上一道很水的树形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