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;

}

你可能感兴趣的:(考研)