zoukankan      html  css  js  c++  java
  • POJ 3189 二分+Dinic

    题意:
    这里写图片描述
    这里写图片描述
    思路:
    二分跨度 枚举最低座次
    建图:源点向每头牛连边权为1的边 每头牛向当前枚举的B的区间这段连上边权为1的边 所有座次向汇点连边权为牛棚容量的边
    判判流量是不是等于n

    一开始写得是直接枚举答案,在这个答案下枚举座次最低的值 T了。。

    (然后我看了一发数据 )
    数据中有这样一个点:1000 20 balabala
    答案是20

    这就很蛋疼了 我枚举了200次 略多 (虽然在我电脑上还是能1s之内跑出来 但是POJ评测机并不快啊)

    我就把答案的那个20二分了一下 变成了6

    枚举大概几十次 嗯 A了 938ms

    //By SiriusRen
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 1055
    int n,b,map[N][25],B[25],e=1050,answer;
    struct Dinic{
        int first[N],next[60*N],v[60*N],w[60*N],vis[N],tot;
        void add(int x,int y,int z){w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;}
        bool tell(){
            memset(vis,-1,sizeof(vis));
            queue<int>q;q.push(0);vis[0]=0;
            while(!q.empty()){
                int t=q.front();q.pop();
                for(int i=first[t];~i;i=next[i])
                    if(w[i]&&vis[v[i]]==-1)
                        q.push(v[i]),vis[v[i]]=vis[t]+1;
            }
            return vis[e]!=-1;
        }
        int zeng(int x,int y){
            if(x==e)return y;
            int r=0;
            for(int i=first[x];~i&&y>r;i=next[i])
                if(vis[v[i]]==vis[x]+1&&w[i]){
                    int t=zeng(v[i],min(w[i],y-r));
                    w[i]-=t,w[i^1]+=t,r+=t;
                }
            if(!r)vis[x]=-1;
            return r;
        }
        int flow(){
            int ans=0,jy;
            while(tell())while(jy=zeng(0,0x3fffffff))ans+=jy;
            return ans;
        }
        bool solve(int begin,int end){
            memset(first,-1,sizeof(first)),tot=0;
            for(int i=1;i<=n;i++)
                for(int j=begin;j<=end;j++)
                    add(i,1000+map[i][j],1),add(1000+map[i][j],i,0);
            for(int i=1;i<=b;i++)add(1000+i,e,B[i]),add(e,1000+i,0);
            for(int i=1;i<=n;i++)add(0,i,1),add(i,0,0);
            return flow()==n;
        }
    }dinic;
    int main(){
        scanf("%d%d",&n,&b);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=b;j++)
                scanf("%d",&map[i][j]);
        for(int i=1;i<=b;i++)scanf("%d",&B[i]);
        int l=0,r=b;
        while(l<=r){
            int Mid=(l+r)>>1;
            for(int i=1;i+Mid<=b;i++)
                if(dinic.solve(i,i+Mid)){
                    answer=Mid,r=Mid-1;
                    goto ed;
                }
            l=Mid+1;
            ed:;
        }
        printf("%d
    ",answer+1);
    }

    这里写图片描述

  • 相关阅读:
    python数据类型:字典Dictionary
    python数据类型:元组
    python数据类型:列表List和Set
    python数据类型:字符串
    python数据类型:Number数字
    Python控制语句
    Python运算符
    python基础语法
    Linux shell Script初识
    linux awk详解
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532242.html
Copyright © 2011-2022 走看看