最近做了關於樹形dp的相關題目,現在做一下總結,第一道題目便是hdu2242,題目爲中文描述,題意不便多說
解題思路:本題沒有保證給出的圖是一顆數,他可能出現聯通的情況,因此我們需要進行縮點操作,然要纔將其視爲一棵樹來解決,dfs過程就是用dp[root]表示以root爲根節點的字數的結點個數,最後求出n-2*dp[i]最小即可,此題的關鍵還是所點操作。
代碼:
//#pragma comment(linker, "/STACK:1024000000,1024000000")//預處理棧,避免棧溢出
#include<cstdio>
#include<queue>
#include<stack>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 20005
stack<int>q;
int dfn[N],low[N],bb[N];
int ans,sum;
int dp[N];
int aa[N];
int sum1[N];
struct node
{
int st,en,next;
}e1[2*N],e2[2*N];
int num1,num2,p1[N],p2[N],num,dfs_clock;
void init()
{
num=dfs_clock=num1=num2=0;
memset(p1,-1,sizeof(p1));
memset(p2,-1,sizeof(p2));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(dp,0,sizeof(dp));
memset(sum1,0,sizeof(sum1));
ans=100000000;
}
void add1(int st,int en)
{
e1[num1].st=st;
e1[num1].en=en;
e1[num1].next=p1[st];
p1[st]=num1++;
}
void add2(int st,int en)
{
e2[num2].st=st;
e2[num2].en=en;
e2[num2].next=p2[st];
p2[st]=num2++;
}
void dfs1(int root,int fa)
{
int fg=1;
low[root]=dfn[root]=++dfs_clock;
q.push(root);
for(int i=p1[root];i+1;i=e1[i].next)
{
int son=e1[i].en;
if(son==fa&&fg)
{
fg=0;//處理有重邊的情況
continue;
}
if(dfn[son]==0)
{
dfs1(son,root);
low[root]=min(low[son],low[root]);
}
else
{
low[root]=min(low[root],dfn[son]);
}
}
if(dfn[root]==low[root])
{
num++;
while(1)//縮點操作
{
int xx=q.top();
q.pop();
bb[xx]=num;
sum1[num]+=aa[xx];
if(xx==root)break;
}
}
}
void dfs2(int root,int fa)
{
dp[root]=sum1[root];
for(int i=p2[root];i+1;i=e2[i].next)
{
int son=e2[i].en;
if(son==fa)continue;
dfs2(son,root);
dp[root]+=dp[son];
}
}
int main()
{
int n,m,a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&aa[i]);
sum+=aa[i];
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
a++,b++;
add1(a,b);
add1(b,a);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
dfs1(i,0);
}
}
if(num==1)
{
printf("impossible\n");
continue;
}
for(int i=1;i<=n;i++)
{
for(int j=p1[i];j!=-1;j=e1[j].next)
{
if(bb[e1[j].st]!=bb[e1[j].en])
{
add2(bb[e1[j].st],bb[e1[j].en]);//縮點後重新見圖,便是一顆樹
//add2(bb[e1[j].en],bb[e1[j].st]);
}
}
}
dfs2(1,0);
for(int i=1;i<=num;i++)
{
ans=min(abs(sum-2*dp[i]),ans);
}
printf("%d\n",ans);
}
return 0;
}