HDOJ 2242 考研路茫茫——空调教室

题意:给一个无向图连通,图中每个结点都有一个权值,问能否割掉图中的一条边,使得图变为2个连通支,若能,使2个连通支中权值和的差最小,输出差的绝对值。N<=10^4

分析:dfs时用tarjan判断边是否为割边,若是就更新答案。需注意的是有重边。

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 10000
#define M 20000
#define INF 0x3f3f3f3f
int n,m,e,w[N];
int sum,num[N];
int first[N],next[M<<1],v[M<<1],cnt[M<<1];
int dfn[N],low[N],id,ans;
void init()
{
    e=sum=id=0;
    ans=INF;
    memset(first,-1,sizeof(first));
    memset(cnt,0,sizeof(cnt));
    memset(dfn,0,sizeof(dfn));
    memset(num,0,sizeof(num));
}
void add(int a,int b)
{
    for(int i=first[a];~i;i=next[i])
    {
        if(v[i]==b)
        {
            cnt[i]++;
            return;
        }
    }
    cnt[e]++;
    v[e]=b;
    next[e]=first[a];
    first[a]=e++;
}
void dfs(int a,int fa)
{
    dfn[a]=low[a]=++id;
    num[a]=w[a];
    int i,b;
    for(i=first[a];~i;i=next[i])
    {
        b=v[i];
        if(dfn[b])
        {
            if(b^fa)    low[a]=min(low[a],dfn[b]);
        }
        else
        {
            dfs(b,a);
            num[a]+=num[b];
            low[a]=min(low[a],low[b]);
            if(low[b]>dfn[a] && cnt[i]<2)
            {
                ans=min(ans,abs(sum-2*num[b]));
            }
        }
    }
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=0;i<n;i++)
        {
            scanf("%d",&w[i]);
            sum+=w[i];
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        dfs(0,-1);
        if(ans<INF) printf("%d\n",ans);
        else    puts("impossible");
    }
    return 0;
}
posted @ 2012-09-17 17:24  BeatLJ  阅读(225)  评论(0编辑  收藏  举报