hdu2242(树形dp+tarjan+缩点)

hdu2242 http://acm.hdu.edu.cn/showproblem.php?pid=2242

给定n,m表示n个点,m条边

每个点有个权值

问我们删除两某条边(割边)后将图分为两个部分,要使得两个部分的权值之差最小

这题的弱化版本是在一棵树上删除某条边后后将图分为两个部分,要使得两个部分的权值之差最小。是用树形dp来做的

但是这道题目是个图,但是我们可以转化为树,即将图中的边连通分量求出来,然后缩成一个点,建出一个新的树图,那么就可以用树形dp来求解题目了.

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 typedef long long LL;                   
 15 const int INF = 1<<30;
 16 const int N = 10000 + 10;
 17 vector<int> g1[N],g2[N];
 18 int val1[N],val2[N];
 19 int dfn[N],low[N],dfs_clock,cnt;
 20 int belong[N];
 21 stack<int> st;
 22 bool vis[N];
 23 int ans,sum;
 24 void tarjan(int u, int fa)
 25 {
 26     bool flag = false;
 27     vis[u] = true;
 28     dfn[u] = low[u] = ++dfs_clock;
 29     st.push(u);
 30     for(int i=0; i<g1[u].size(); ++i)
 31     {
 32         
 33         int v = g1[u][i];
 34         if(v==fa && !flag) 
 35         {
 36             flag = true;
 37             continue;
 38         }
 39         if(!vis[v]) tarjan(v,u);
 40         low[u] = min(low[u],low[v]);
 41     }
 42     if(dfn[u]==low[u])
 43     {
 44         cnt++;
 45         int x;
 46         do
 47         {
 48             x= st.top();
 49             st.pop();
 50             belong[x] = cnt;
 51             val2[cnt] += val1[x];
 52         }while(u!=x);
 53     }
 54 }
 55 
 56 void dfs(int u, int fa)
 57 {
 58     vis[u] = true;
 59     for(int i=0; i<g2[u].size(); ++i)
 60     {
 61         int v = g2[u][i];
 62         if(vis[v]) continue;
 63         dfs(v,u);
 64         val2[u] += val2[v];
 65     }
 66 }
 67 void dfs2(int u, int fa)
 68 {
 69     vis[u] = true;
 70     for(int i=0; i<g2[u].size(); ++i)
 71     {
 72         int v = g2[u][i];
 73         if(vis[v]) continue;
 74         ans = min(ans,abs(sum-2*val2[v]));
 75         dfs2(v,u);
 76     }
 77 }
 78 int main()
 79 {
 80     int n,m,i,u,v,j;
 81     while(scanf("%d%d",&n,&m)!=EOF)
 82     {
 83         for(i=0; i<=n; ++i)
 84         {
 85             g1[i].clear();
 86             g2[i].clear();
 87         }
 88         sum = 0;
 89         for(i=0; i<n; ++i)
 90         {
 91             scanf("%d",&val1[i]);
 92             sum += val1[i];
 93         }    
 94         for(i=0; i<m; ++i)
 95         {
 96             scanf("%d%d",&u,&v);
 97             g1[u].push_back(v);
 98             g1[v].push_back(u);
 99         }
100         memset(vis,0,sizeof(vis));
101         memset(dfn,0,sizeof(dfn));
102         memset(low,0,sizeof(low));
103         memset(val2,0,sizeof(val2));
104         dfs_clock = 0;
105         cnt = 0;
106         tarjan(0,-1);
107         for(i=0; i<n; ++i)
108             for(j=0; j<g1[i].size(); ++j)
109             {
110                 int v = g1[i][j];
111                 if(belong[v] != belong[i])//建新图,虽然新建的图会有重边,但是不影响树形dp
112                 {
113                     g2[belong[i]].push_back(belong[v]);
114                     g2[belong[v]].push_back(belong[i]);
115                 }
116             }
117         if(cnt==1)//如果整个图是边连通的,那么不管删哪条边都不能使得图不连通
118         {
119             puts("impossible");
120             continue;
121         }    
122         ans = INF;
123         memset(vis,0,sizeof(vis));
124         dfs(1,-1);
125         memset(vis,0,sizeof(vis));
126         dfs2(1,-1);
127         printf("%d
",ans);
128     }
129     return 0;
130 }
View Code
原文地址:https://www.cnblogs.com/justPassBy/p/4442356.html