zoukankan      html  css  js  c++  java
  • bzoj1433

     

    1433: [ZJOI2009]假期的宿舍

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3371  Solved: 1425
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    1
    3
    1 1 0
    0 1 0
    0 1 1
    1 0 0
    1 0 0

    Sample Output

    ˆ ˆ

    HINT

    对于30% 的数据满足1 ≤ n ≤ 12。
    对于100% 的数据满足1 ≤ n ≤ 50,1 ≤ T ≤ 20。

    我的方法跟网上其他博客有点不一样,随便YY的。把每个人拆成2个点ai bi,建立超级源汇S,T。

      (1)S向所有 外校人员的ai建立容量1的边

      (2)所有 在校的要回家的学生的bi向T连容量为1的边

      (3)对于一对相互认识的人bi->aj互相建容量无穷边

      (4)每个人的ai向bi建立容量1的边

      这样以后一个流就表示一个挪动方案

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define inf 0x3f3f3f3f
    #define ll long long
    #define N 105 
    using namespace std;
    int n,S,T,tot,cur[N],st[N],hd[N],gh[N],kn[N][N],d[N],vis[N];
    struct edge{int v,next,cap,flow;}e[N*N*4];
    void adde(int u,int v,int c){
        e[tot].v=v;
        e[tot].next=hd[u];
        e[tot].cap=c;
        e[tot].flow=0;
        hd[u]=tot++;
    }
    
    bool bfs(){
        queue<int>q;
        memset(vis,0,sizeof(vis));
        q.push(S);d[S]=0;
        while(!q.empty()){
            int u=q.front();q.pop();vis[u]=1;
            for(int i=hd[u];~i;i=e[i].next){
                int v=e[i].v;
                if(e[i].cap<=e[i].flow||vis[v])continue;
                d[v]=d[u]+1;q.push(v);
            }
        }
        return vis[T];
    }
    
    int dfs(int u,int a){
        if(u==T||!a)return a;
        int fl=0,f;
        for(int i=hd[u];~i;i=e[i].next){
            int v=e[i].v;
            if(d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap-e[i].flow,a)))){
                fl+=f;a-=f;
                e[i].flow+=f;
                e[i^1].flow-=f;
                if(a<=0)break;
            }
        }
        return fl;
    }
    int main(){
    #ifdef wsy
        freopen("data.in","r",stdin);
    #else
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
    #endif
        int cas;scanf("%d",&cas);
        while(cas--){
            scanf("%d",&n);S=0;T=2*n+1;tot=0;
            memset(hd,-1,sizeof(hd));
            for(int i=1;i<=n;i++)scanf("%d",&st[i]);
            
        //    for(int i=1;i<=n;i++)if(!st[i])printf("%d ",i);puts("");
            
            for(int i=1;i<=n;i++)scanf("%d",&gh[i]);
            
        //    for(int i=1;i<=n;i++)if(st[i]&&gh[i])printf("%d ",i);puts("");
            
            for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            scanf("%d",&kn[i][j]);
            for(int i=1;i<=n;i++){
                if(st[i]){
                    if(gh[i])adde(i+n,T,1),adde(T,i+n,0);
                }
                else adde(S,i,1),adde(i,S,0);
            }
            for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++){
                if(!kn[i][j])continue;
            //    printf("%d %d
    ",i,j);
                int f1=st[i],f2=st[j];
                if(f1)adde(j+n,i,inf),adde(i,j+n,0);
                if(f2)adde(i+n,j,inf),adde(j,i+n,0);
            }
            for(int i=1;i<=n;i++)
            adde(i,i+n,1),adde(i+n,i,0);
            while(bfs()){
                for(int i=S;i<=T;i++)cur[i]=hd[i];
                dfs(S,0x3f3f3f3f);
            }
            int fg=0;
            for(int i=hd[S];~i;i=e[i].next)
            if(e[i].cap-e[i].flow>0)fg=1;
            if(fg)puts("T_T");
            else puts("^_^");
        }
        return 0;
    }
    

      

  • 相关阅读:
    最大团问题
    树的重心与相关性质
    2020年牛客算法入门课练习赛3 B
    牛客练习赛66 E
    浅谈后缀数组SA
    [随机化算法] 听天由命?浅谈Simulate Anneal模拟退火算法
    “优美的暴力”——树上启发式合并
    [线段树系列] LCT打延迟标记的正确姿势
    [Tarjan系列] Tarjan算法与有向图的SCC
    [Tarjan系列] 无向图e-DCC和v-DCC的缩点
  • 原文地址:https://www.cnblogs.com/wsy01/p/7932130.html
Copyright © 2011-2022 走看看