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);
}

这里写图片描述

转载于:https://www.cnblogs.com/SiriusRen/p/6532242.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值