HDU 2242 考研路茫茫——空调教室【双连通分量+dp】

题意: 有 n 个教室组成一个连通图,知道了m条无向边,现在要去掉一条边使得这些教室分成两个连通的集合,问是否可以做到,如果可以找出两个集合人数

         的最小差值。

分析: 因为所有的在同一个双连通分量中的人都必须在一个集合里,可以先求出所有的双连通分量并染色,然后用树形DP求出最小差值即可。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
#define maxn 100005
#define maxm 1000005
struct node
{
    int to,next;
}e[maxm],ed[maxm];
int tot;
int tt;
int head[maxn];
int dph[maxn];
void add(int s,int t)
{
    e[tot].to=t;
    e[tot].next=head[s];
    head[s]=tot++;
}
void add2(int s,int t)
{
    ed[tt].to=t;
    ed[tt].next=dph[s];
    dph[s]=tt++;
}
int top,sn,ti,n,m,sum;
int dfn[maxn];
int low[maxn];
int col[maxn];
int sta[maxn];
int val[maxn];
int w[maxn];
void tarjan(int p,int u)
{
    dfn[u]=low[u]=++ti;
    sta[++top]=u;
    int i,k,flag=0;
    for(i=head[u];i;i=e[i].next)
    {
        k=e[i].to;
        if(k==p&&!flag)
        {
            flag=1;
            continue;
        }
        if(dfn[k]==0)
            tarjan(u,k);
        low[u]=min(low[u],low[k]);
    }
    if(dfn[u]==low[u])
    {
        sn++;
        do
        {
            k=sta[top--];
            col[k]=sn;
            val[sn]+=w[k];
        }while(k!=u&&top>0);
    }
}
int res;
int ab(int x)
{  return x>0?x:-x; }
int dfs(int p,int u)
{
    int i,k;
    int tmp=val[u];
    if(res==0)
        return 0;
    for(i=dph[u];i;i=ed[i].next)
    {
        k=ed[i].to;
        if(k!=p)
            tmp+=dfs(u,k);
    }
    res=min(res,ab(sum-2*tmp));
    return tmp;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j,k;
        sum=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&w[i]);
            sum+=w[i];
        }
        int a,b;
        tot=1;
        clr(head);
        while(m--)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        clr(dfn);
        clr(val);
        top=sn=ti=0;
        tarjan(0,0);
        if(sn==1)
        {
            printf("impossible\n");
            continue;
        }
        tt=1;
        clr(dph);
        for(i=0;i<n;i++)
            for(j=head[i];j;j=e[j].next)
            {
                k=e[j].to;
                if(col[i]!=col[k])
                    add2(col[i],col[k]);
            }

        res=999999999;
        dfs(0,1);
        printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-10-02 13:27  'wind  阅读(234)  评论(0编辑  收藏  举报