zoukankan      html  css  js  c++  java
  • 考研路茫茫——空调教室 强连通 双联通分量

    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
  • 相关阅读:
    [leetcode] 48. 旋转图像(Java)(模拟)
    [leetcode] 47. 全排列 II
    [leetcode] 46. 全排列(Java)
    [leetcode] 45. 跳跃游戏 II(Java)(动态规划)
    [leetcode] 875. 爱吃香蕉的珂珂(周赛)
    [leetcode] 874. 行走机器人模拟(周赛)
    《数据结构与算法分析:C语言描述》复习——第八章“并查集”——并查集
    《数据结构与算法分析:C语言描述》复习——第六章“排序”——基数排序
    《数据结构与算法分析:C语言描述》复习——第六章“排序”——桶排序
    《数据结构与算法分析:C语言描述》复习——第六章“排序”——快速排序
  • 原文地址:https://www.cnblogs.com/bxd123/p/10800039.html
Copyright © 2011-2022 走看看