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\n",answer+1);
}

这里写图片描述

posted @ 2016-10-23 17:36  SiriusRen  阅读(87)  评论(0编辑  收藏  举报