hdu2242

来源:互联网 发布:java中类的初始化顺序 编辑:程序博客网 时间:2024/05/20 22:29


     最近做了关于树形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 20005stack<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;}


0 0
原创粉丝点击