hdu 2242双联通分量+树形dp

/*先求出双联通缩点,然后进行树形dp*/
#include<stdio.h>
#include<string.h>
#include<math.h>
#define inf 0x3fffffff
#define N  11000
struct node
{
    int u,v,next;
} bian[N*4],edge[N*4];
int head[N],yong,dfn[N],low[N],index,f[N*4],cnt,n,num[N];
int yon;
int belong[N],tot[N];
int visit[N],dp[N];
void init()
{
    memset(head,-1,sizeof(head));
    yong=0;
    index=0;
    cnt=0;
    memset(dfn,0,sizeof(dfn));
    memset(f,0,sizeof(f));
    memset(low,0,sizeof(low));
}
int Min(int a,int b)
{
    return a>b?b:a;
}
void addedge(int u,int v)  //一次建图
{
    bian[yong].u=u;
    bian[yong].v=v;
    bian[yong].next=head[u];
    head[u]=yong++;
}
void tarjan(int u,int pre ) //tarjan算法求桥
{
    dfn[u]=low[u]=++index;
    int i;
    for(i=head[u]; i!=-1; i=bian[i].next)
    {
        int v=bian[i].v;
        if(i==(pre^1))continue;
        if(!dfn[v])
        {
            tarjan(v,i);
            low[u]=Min(low[u],low[v]);
            if(low[v]>dfn[u])
            {
                cnt=1;//是否存在桥
                f[i]=f[i^1]=1;//标记桥
            }
        }
        else
            low[u]=Min(low[u],dfn[v]);
    }
    return ;
}
void dfs(int u,int pre)
{
    belong[u]=cnt;//缩
    tot[cnt]+=num[u];//记录缩点的权值
    int i,v;
    for(i=head[u]; i!=-1; i=bian[i].next)
    {
        v=bian[i].v;
        if(!f[i]&&!belong[v]&&i!=(pre^1))
            dfs(v,i);
    }
    return ;
}
void addedge1(int u,int v)  //二次建图
{
    edge[yon].u=u;
    edge[yon].v=v;
    edge[yon].next=head[u];
    head[u]=yon++;
}
void slove()
{
    int i;
    memset(belong,0,sizeof(belong));
    memset(tot,0,sizeof(tot));
    cnt=0;
    for(i=1; i<=n; i++)
        if(!belong[i])  //缩点
        {
            cnt++;
            dfs(i,-1);
        }
    memset(head,-1,sizeof(head));
    yon=0;
    for(i=0; i<yong; i++) //重新建图
    {
        int u=bian[i].u,v=bian[i].v;
        if(belong[u]!=belong[v])
        {
            addedge1(belong[u],belong[v]);
            addedge1(belong[v],belong[u]);
            //      printf("%d %d\n",belong[u],belong[v]);
        }
    }
    return ;
}

int dfs1(int u)  //为树形图求出他和他的子节点的权值
{
    visit[u]=1;
    int i,v,sum=0;
    sum+=tot[u];
    for(i=head[u]; i!=-1; i=edge[i].next)
    {
        v=edge[i].v;
        if(!visit[v])
        {
            sum+=dfs1(v);
        }
    }
//printf("%d %d\n",u,sum);
    dp[u]=sum;
    return sum;
}
int main()
{
    int m,i,j,k,a,b,c,sum,minn;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        sum=0;
        init();
        for(i=1; i<=n; i++)
        {
            scanf("%d",&num[i]);
            sum+=num[i];
        }
        while(m--)
        {
            scanf("%d%d",&a,&b);
            a++;
            b++;
            addedge(a,b);
            addedge(b,a);
        }
        tarjan(1,-1);
        if(cnt==0)  //如果不存在桥
        {
            printf("impossible\n");
            continue;
        }
        slove();
        memset(visit,0,sizeof(visit));
        dfs1(1);
        minn=inf;
        for(i=1; i<=cnt; i++)
        {
            // printf("%d\n",dp[i]);
            minn=Min(minn,fabs(sum*1.0-2.0*dp[i]));//求最优
        }
        printf("%d\n",minn);
    }
    return 0;
}

posted @ 2014-07-25 11:47  HYDhyd  阅读(130)  评论(0编辑  收藏  举报