1. 程式人生 > >考研路茫茫——空調教室 強連通 雙聯通分量

考研路茫茫——空調教室 強連通 雙聯通分量

如果 sizeof long scrip int 連通 文件 eve 空調

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\n",cnt,num); if(num!=cnt-1||cnt==1) printf("impossible\n"); 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\n",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\n");continue;}
      //  printf("%d\n",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\n",res);
    }
    return 0;
}
View Code

考研路茫茫——空調教室 強連通 雙聯通分量