bzoj1305 [CQOI2009]dance跳舞 最大流 二分

来源:互联网 发布:3d头像制作软件 编辑:程序博客网 时间:2024/04/30 06:58

bzoj1305 [CQOI2009]dance跳舞
题意:一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。 有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。 给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?n<=50
题解:拆点= =
二分答案(枚举也可以orz)
然后就变成判定性问题啦
然后我们看到这是一个二分图
左边代表男孩 右边代表女孩
我们可以愉快的拆点
每个节点拆成3个点 我们依次叫它node1,2,3
二分图左边的每个节点的前两个分点(node1,2)连的边代表最多跳的舞曲数(二分出来的x)
后两个分点(node2,3)连的边代表最多和不喜欢的人跳舞次数(k)
二分图右边的点反过来
然后总源点和左边的所有node1连inf
又边的所有node3和总汇点连inf
左边node3和不喜欢的人的node1连1
左边node2和喜欢的人的node2连1
然后跑最大流 flow==x*n 代表是可行解

#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;bool bfs();int dfs(int,int);int dinic();queue<int>Q;const int inf=1<<30,Maxn=400,Maxm=400*400;struct E{int to,cap,flow,nxt;}edge[Maxm*2];int tot=2,s,t,n,k;int idx[Maxn],a[Maxm],cur[Maxn],dis[Maxn];char map[Maxn][Maxn];bool vis[Maxn];void addedge(int from,int to,int c){    edge[tot].to=to;edge[tot].cap=c;edge[tot].flow=0;edge[tot].nxt=idx[from];idx[from]=tot++;}void add(int from,int to,int cap){addedge(from,to,cap);addedge(to,from,0);}void init(){    scanf("%d%d\n",&n,&k);    for(int i=1;i<=n;i++)        scanf("%s\n",map[i]+1);}int node1(char c,int i){return c=='l'?i:3*n+i;}int node2(char c,int i){return c=='l'?i+n:4*n+i;}int node3(char c,int i){return c=='l'?i+2*n:5*n+i;}void build(int x){    memset(edge,0,sizeof(E));    memset(idx,0,sizeof(idx));tot=2;    s=n*6+1,t=n*6+2;    for(int i=1;i<=n;i++)        add(s,node1('l',i),inf),        add(node3('r',i),t,inf);    for(int i=1;i<=n;i++){        add(node1('l',i),node2('l',i),x);        add(node2('l',i),node3('l',i),k);        add(node2('r',i),node3('r',i),x);        add(node1('r',i),node2('r',i),k);    }    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++){            if(map[i][j]=='Y') add(node2('l',i),node2('r',j),1);            else add(node3('l',i),node1('r',j),1);        }    //printf("\n");}bool judge(int x){return dinic()>=x*n?1:0;}int main(){    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    init();int l=0,r=n+1,i;    /*for(i=1;i<=n;i++){        build(i);        if(!judge(i)) break;    }    printf("%d\n",i-1);*/    while(l<r){        int mid=(l+r)/2;        //printf("%d\n",mid);        build(mid);        if(judge(mid)) l=mid+1;        else r=mid;    }    printf("%d\n",l-1);    return 0;}bool bfs(){    memset(vis,0,sizeof(vis));    memset(dis,0,sizeof(dis));    Q.push(s);vis[s]=1;    while(!Q.empty()){        int x=Q.front();Q.pop();        for(int i=idx[x];i;i=edge[i].nxt){            E e=edge[i];            if(!vis[e.to] && e.cap>e.flow)                 vis[e.to]=1,Q.push(e.to),dis[e.to]=dis[x]+1;        }    }    //for(int i=0;i<=T;i++) printf("%d ",dis[i]);    return vis[t];}int dfs(int x,int a){    int flow=0,f;    if(x==t || a==0) return a;    for(int& i=cur[x];i;i=edge[i].nxt){        E e=edge[i];        if(dis[x]+1==dis[e.to]){            f=dfs(e.to,min(a,e.cap-e.flow));            if(f>0){                edge[i].flow+=f;                edge[i^1].flow-=f;                flow+=f;a-=f;if(!a) break;            }        }    }    return flow;}int dinic(){    int flow=0;    while(bfs()){        for(int i=1;i<=t;i++) cur[i]=idx[i];        flow+=dfs(s,inf);    }    return flow;}
0 0
原创粉丝点击