BZOJ1532/POI2005 Dicing

直接求似乎不簡單,由於題目求”最大值最小問題”,可以轉化爲二分答案來驗證一個解是否成立.假設枚舉的答案是x,那麼所有人贏得的場次都<=x.而每場比賽最多隻有一個人獲勝,我們可以根據此信息,構圖:
設置源點與每個人建邊,每個人與它所參加的每場比賽建邊,每場比賽與超級匯點建邊並且流量設置爲1.根據此圖跑一遍最大流,判斷是否爲m即可.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=10005;
const int oo=1e9+5;
int head[M<<1],n,m,u[M],v[M],ec=0,tot;
int dis[M<<1],flw[M<<1];// dis表示層數 
struct node{
    int to,cap,nex;
}e[M*8];//邊數 (n+3*m)*2 
int Q[M<<2];
inline void rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<1)+(res<<3)+(c^48);
    while(c=getchar(),c>=48);
}
void ins(int a,int b,int c){
    e[ec]=(node){b,c,head[a]};
    head[a]=ec++;
    e[ec]=(node){a,0,head[b]};
    head[b]=ec++;
}
bool BFS(){
    memset(dis,-1,sizeof(dis));
    int L=0,R=0,i,j,k;
    dis[0]=0;
    Q[R++]=0;
    while(L<R){
        int x=Q[L++];
        if(x==tot)return true;
        for(i=head[x];~i;i=e[i].nex){
            int to=e[i].to,cap=e[i].cap;
            if(dis[to]==-1&&cap){
                dis[to]=dis[x]+1;
                Q[R++]=to;
            }
        }
    }
    return false;
}
int dfs(int x,int flw){
    if(x==tot)return flw;
    int now=0;
    for(int i=head[x];~i;i=e[i].nex){
        int to=e[i].to,cap=e[i].cap;
        if(dis[to]!=dis[x]+1||!cap)continue;
        int f=dfs(to,min(flw,cap));
        now+=f;
        e[i].cap-=f;
        e[i^1].cap+=f;
        if(now==flw)break;
    }
    return now;
}
bool chk(int res){
    memset(head,-1,sizeof(head));//初始化
    ec=0;
    int ans=0,i,j,k,a,b;
    for(i=1;i<=n;i++)ins(0,i,res);
    for(i=1;i<=m;i++){
        ins(u[i],i+n,res);
        ins(v[i],i+n,res);
        ins(i+n,tot,1);
    }//構圖
    while(BFS()){
        do a=dfs(0,oo),ans+=a;
        while(a!=0);
    }
    if(ans==m)return true;
    return false;
}
int main(){
    int l,r,i,j,k,ans;
    rd(n);rd(m);tot=n+m+1;
    for(i=1;i<=m;i++){
        rd(v[i]);rd(u[i]);
    }
    l=(m+n-1)/n;r=m;
    while(l<=r){
        int mid=l+r>>1;
        if(chk(mid)){
            ans=mid;r=mid-1;
        }else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章