hdu 2242

http://acm.hdu.edu.cn/showproblem.php?pid=2242 

题目大意:给一个教室群,问能不能把这些教室群分成两部分,并且使两部分之间的权值差最小(每一个教室都有一定的权值);

思路:先用双联通进行缩点,因为那些双向连通的教室肯定是分不开的,所以要把它们缩成一个点。

之后再重新建图,遍历一次树!

需要注意一点这道题的数据包含重边,需要考虑!!

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
const int N = 10005;
struct nd
{
        int from,to,next;
}edge[N*5];
int head[N],n,m,dfn[N],low[N],vis[N],val[N],val1[N],tsum,ans,as[N],idx,st[N],cnt;
int min(int x,int y){ return x>y?y:x;}
void add(int a,int b,int tot)
{
        edge[tot].from = a; edge[tot].to = b;
        edge[tot].next = head[a]; head[a] = tot;
}
void tarjan(int pre,int u,int& count)
{
        int j,v,flag = 0;
        dfn[u] = low[u] = idx++;
        vis[u] = 1;
        st[cnt++] = u;
        for(j = head[u]; j != -1; j=edge[j].next)
        {
                v = edge[j].to;
                if(v==pre&&!flag){flag=1;continue;}//重边处理
                if(!vis[v]) tarjan(u,v,count);
                low[u] = min(low[u],low[v]);
        }
        if(dfn[u]==low[u])
        {
                count++;
                do{
                        v = st[--cnt];
                        as[v] = count;
                        val[count] += val1[v];
                }while(v!=u&&cnt>=0);
        }
}
int dfs(int u,int pre)
{
        int j,v,sum = val[u];
        if(!ans)return 0;
        for(j = head[u]; j != -1; j = edge[j].next)
        {
                v = edge[j].to;
                if(v!=pre) sum += dfs(v,u);
        }
        ans = min(ans,abs(tsum-sum*2));
        return sum;
}
int main()
{
        int i,a,b,tot,count;
        while(scanf("%d %d",&n,&m)==2)
        {
                memset(head,-1,sizeof(head));
                tsum = 0;
                tot = 0;
                for(i = 0; i < n; ++ i){ scanf("%d",val1+i); tsum += val1[i]; }
                for(i = 0; i < m; ++ i)
                {
                        scanf("%d %d",&a,&b);
                        add(a,b,tot); tot++;
                        add(b,a,tot); tot++;
                }
                memset(vis,0,sizeof(vis));
                memset(val,0,sizeof(val));
                count = 0; idx = 0;
                tarjan(0,0,count);
                if(count==1){ puts("impossible"); continue;}
                memset(head,-1,sizeof(head));
                int k = 0;
                for(i = 0; i < tot; ++ i)
                {
                        a = edge[i].from;
                        b = edge[i].to;
                        if(as[a]!=as[b]){ add(as[a],as[b],k);++k;}
                }
                cnt = 0;
                ans = 1<<30;
                dfs(1,0);
                printf("%d\n",ans);
        }return 0;
}

posted on 2012-06-18 14:34  aigoruan  阅读(150)  评论(0)    收藏  举报

导航