hdu 2242(边双连通分量)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2242

思路:Tarjan求边双连通分量,进行缩点后成树,然后就是树型dp,求一下最小差值就行了。

ps:注意点:由于双向建边,DP搜索时要记录父亲,只能往下搜,不能搜该节点的父亲。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stack>
 6 #include<vector>
 7 using namespace std;
 8 #define MAXN 10000+10
 9 #define inf 1<<30
10 stack<int>S;
11 vector<int>vet[MAXN];
12 vector<int>map[MAXN];
13 int n,m,cnt,_count,sum,MIN;
14 int dfn[MAXN],low[MAXN];
15 bool mark[MAXN];
16 int color[MAXN];
17 int dp[MAXN];
18 int value[MAXN];
19 
20 //tarjan算法找边双联通分量并进行缩点
21 void Tarjan(int u,int father){
22    int flag=0;
23    dfn[u]=low[u]=++cnt;
24    mark[u]=true;
25    S.push(u);
26    for(int i=0;i<vet[u].size();i++){
27       int v=vet[u][i];
28       if(v==father&&!flag){ flag=1;continue; }//考虑重边情况,重要
29       if(!mark[v])Tarjan(v,u);
30       low[u]=min(low[u],low[v]);
31    }
32    if(low[u]==dfn[u]){
33       _count++;
34       int v;
35       do{
36          v=S.top();
37          S.pop();
38          color[v]=_count;//染色
39          dp[_count]+=value[v];//求缩点后的价值
40       }while(u!=v);
41    }
42 }
43 
44 //树型dp求最小差值
45 int dfs(int u,int father){
46    int ans=dp[u];
47    for(int i=0;i<map[u].size();i++){
48       int v=map[u][i];
49       if(v==father)continue;
50       ans+=dfs(v,u);
51    }
52    MIN=min(MIN,abs((sum-ans)-ans));
53    return ans;
54 }
55 
56 
57 
58 int main(){
59 //   freopen("1.txt","r",stdin);
60    int u,v;
61    while(~scanf("%d%d",&n,&m)){
62       sum=cnt=_count=0;MIN=inf;
63       for(int i=0;i<=n;i++){ vet[i].clear();map[i].clear(); }
64       for(int i=0;i<n;i++){ scanf("%d",&value[i]);sum+=value[i]; }
65       while(m--){
66          scanf("%d%d",&u,&v);
67          vet[u].push_back(v);
68          vet[v].push_back(u);
69       }
70       memset(color,0,sizeof(color));
71       memset(dfn,0,sizeof(dfn));
72       memset(low,0,sizeof(low));
73       memset(mark,false,sizeof(mark));
74       memset(dp,0,sizeof(dp));
75       Tarjan(0,0);
76       if(_count==1){ puts("impossible");continue; }
77       for(int i=0;i<n;i++){
78          for(int j=0;j<vet[i].size();j++){
79             if(color[i]!=color[vet[i][j]]){
80                map[color[i]].push_back(color[vet[i][j]]);
81             }
82          }
83       }
84       dfs(1,0);
85       printf("%d\n",MIN);
86    }
87    return 0;
88 }
View Code
原文地址:https://www.cnblogs.com/wally/p/3117913.html