考研路茫茫——空调教室 强连通 双联通分量

Problem Description
众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们。Lele也是其中一个。而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY。

一个炎热的下午,Lele照例在教室睡觉的时候,竟然做起了空调教室的美梦。

Lele梦到学校某天终于大发慈悲给某个教室安上了一个空调。而且建造了了M条通气管道,让整个教学楼的全部教室都直接或间接和空调教室连通上,构成了教室群,于是,全部教室都能吹到空调了。

不仅仅这样,学校发现教室人数越来越多,单单一个空调已经不能满足大家的需求。于是,学校决定封闭掉一条通气管道,把全部教室分成两个连通的教室群,再在那个没有空调的教室群里添置一个空调。

当然,为了让效果更好,学校想让这两个教室群里的学生人数尽量平衡。于是学校找到了你,问你封闭哪条通气管道,使得两个教室群的人数尽量平衡,并且输出人数差值的绝对值。
 
Input
本题目包含多组数据,请处理到文件结束。
每组测试第一行包含两个整数N和M(0<N<=10000,0<M<20000)。其中N表示教室的数目(教室编号从0到N-1),M表示通气管道的数目。
第二行有N个整数Vi(0<=Vi<=1000),分别代表每个教室的人数。
接下来有M行,每行两个整数Ai,Bi(0<=Ai,Bi<N),表示教室Ai和教室Bi之间建了一个通气管道。
 
Output
对于每组数据,请在一行里面输出所求的差值。
如果不管封闭哪条管道都不能把教室分成两个教室群,就输出"impossible"。
 
Sample Input
4 3 1 1 1 1 0 1 1 2 2 3 4 3 1 2 3 5 0 1 1 2 2 3
 
Sample Output
0 1

用拓扑排序 各种数据都过了  死活wa

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 0x3f3f3f3f
const int N=10000+5;
const int M=2*N;
int head[M],pos;
struct Edge
{
    int nex,to;
}edge[M];
void add(int a,int b)
{
    edge[++pos].nex=head[a];
    head[a]=pos;
    edge[pos].to=b;
}
int tot,ind,cnt,Stack[N],dfn[N],low[N],vis[N],belong[N],node[N],peo[N],in[N];
int n,m;
vector<int>G[N];

void init()
{
    pos=tot=ind=cnt=0;
    CLR(Stack,0);
    CLR(in,0);
    CLR(peo,0);
    CLR(head,0);
    CLR(vis,0);
    CLR(dfn,0);
    CLR(low,0);
}
void tarjan(int x)
{
    dfn[x]=low[x]=++tot;
    Stack[++ind]=x;
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v])
            low[x]=min(low[x],low[v]);
    }
    if(dfn[x]==low[x])
    {
        cnt++;int v;
        do
        {
            v=Stack[ind--];
            vis[v]=0;
            belong[v]=cnt;
            peo[cnt]+=node[v];
        }
        while(x!=v);
    }
}

int main()
{
    while(~RII(n,m))
    {
        int sum=0;
        rep(i,1,n)RI(node[i]),sum+=node[i];
        rep(i,1,m)
        {
            int a,b;RII(a,b);
            a++;b++;
            add(a,b);
            add(b,a);
        }
        cnt=0;
        rep(i,1,n)
        if(!dfn[i])tarjan(i);

        int num=0;
        rep(i,1,n)
        {
            int u=belong[i];
            for(int j=head[i];j;j=edge[j].nex)
            {
                int v=belong[ edge[j].to ];
                if(u!=v)
                {
                    int ok=1;
                    if(G[u].size())
                    rep(i,0,G[u].size()-1)
                    {
                        if(G[u][i]==v)ok=0;
                    }
                    if(ok)G[u].pb(v),in[v]++,num++;
                }
            }
        }

        printf("cnt=%d num=%d
",cnt,num);
        if(num!=cnt-1||cnt==1)
            printf("impossible
");
        else
        {
            queue<int>q;
            CLR(node,0);
            rep(i,1,cnt)
            if(!in[i])
            {
                node[i]=peo[i];
                q.push(i);
            }
            int ans=inf;
            while(!q.empty())
            {
                int u=q.front();q.pop();
                ans=min(ans,abs( sum-node[u]-node[u]  ));
                if(G[u].size())
                rep(i,0,G[u].size()-1)
                {
                    int v=G[u][i];

                    node[v]+=node[u];
                    ans=min(ans,abs( sum-node[v]-node[v]  ));
                    if(--in[v]==0)
                    {
                        node[v]+=peo[v];
                        ans=min(ans,abs( sum-node[v]-node[v]  ));
                        q.push(v);
                    }
                }
            }
            printf("%d
",ans);
        }
        rep(i,1,cnt)
        G[i].clear();
        init();

    }
    return 0;
}
View Code

原来是双联通分量  顶不住了 待补

贴上大佬代码:

#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10005;
const int maxm = 20005;
int n,m;
int va[maxn];
struct node
{
    int to;
    int next;
    node(){}
    node(int a,int b):to(a),next(b){}
}edge[maxm<<1],tree[maxm<<1];
int head[maxn],dfn[maxn],low[maxn],belong[maxn],thead[maxn],ans[maxn];
int tot,ti,coun,ttot,res,people;
stack<int>s;
void add_edge(int u,int v)
{
    edge[tot] = node(v,head[u]);
    head[u] = tot++;
    edge[tot] = node(u,head[v]);
    head[v] = tot++;
}
void tarjan(int u,int fa)
{
    dfn[u] = ++ti; low[u] = ti; s.push(u);
    int flag = 0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v = edge[i].to;
        if(v==fa&&flag==0){flag = 1;continue;}
        if(!dfn[v]){
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
        }else if(belong[v]==-1) low[u] = min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        int y;
        coun++;
        do{
            y = s.top(); s.pop();
            ans[coun] += va[y];
            belong[y] = coun;
        }while(y!=u);
    }
}
int cbh(int u,int fa)
{
    int sum = ans[u];
    dfn[u] = 1;
    for(int i=thead[u];i!=-1;i=tree[i].next)
    {
        int v = tree[i].to;
        if(v==fa||dfn[v]) continue;
        sum+=cbh(v,u);
    }
    res = min(res,abs(2*sum-people));
    return sum;
}
int main()
{
    int u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        people = 0;
        for(int i=0;i<n;i++) scanf("%d",&va[i]),people+=va[i];
        tot = 0;
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;i++)
        {
           scanf("%d%d",&u,&v);
           add_edge(u,v);
        }
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(ans,0,sizeof(ans));
        memset(belong,-1,sizeof(belong));
        coun = 0;ti = 0;
        tarjan(0,0);
        if(coun==1){printf("impossible
");continue;}
      //  printf("%d
",coun);
        ttot = 0;
        memset(thead,-1,sizeof(thead));
        memset(dfn,0,sizeof(dfn));
        for(int i=0;i<n;i++)
        {
            for(int j=head[i];j!=-1;j=edge[j].next)
            {
                v = edge[j].to;
                if(belong[i]!=belong[v])
                {
                    tree[ttot] = node(belong[v],thead[belong[i]]);
                    thead[belong[i]] = ttot++;
                }
            }
        }
        res = 0xfffffff;
        cbh(1,0);
        printf("%d
",res);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/bxd123/p/10800039.html