BZOJ-1305: [CQOI2009]dance跳舞(最大流 增加超级源汇+分裂点+二分 水题)

1305: [CQOI2009]dance跳舞

Time Limit: 5 Sec  Memory Limit: 162 MB

Description

一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

Input

第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为‘Y‘当且仅当男孩i和女孩j相互喜欢。

Output

仅一个数,即舞曲数目的最大值。

Sample Input

3 0
YYY
YYY
YYY

Sample Output

3

HINT

N<=50 K<=30

垃圾网络流1A,增加超级源汇+分裂点+最大流+二分。

男,女各分裂成喜欢yes和不喜欢no两个点

若男女是cp,则每个男yes-->每个女yes 容量1

若男女不是cp,则每个男no-->每个女no 容量1

控制:每个男孩都不会和同一个女孩跳两首(或更多)舞曲。

每个男yes-->自己no 容量k

每个女no-->自己yes 容量k

控制:每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。

最后二分x(暴力枚举ok,数据弱爆了!)

S--->每个男yes 容量x

每个女yes--->T 容量x

若最大流==x*人数(即满流) 则成立。

控制:每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。

ISAP!!!跑的飞快。。。

#include<iostream>
#include<fstream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<deque>
#include<utility>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<sstream>
#include<cstring>
#include<bitset>
#include<stack>
using namespace std;

int n,m,s,t,cnt,x,y,z,k,ans;
char ss[55][55];
struct sdt
{
    int cap,flow,u,v;
}e[200005];
int nxt[200005],fir[10005],d[10005],par[10005],num[10005],cur[10005];
bool vis[10005];

int read()
{
	int x=0;char c=getchar();
	while(c<48||c>57)c=getchar();
	while(c>47&&c<58)x*=10,x+=c-48,c=getchar();
	return x;
}

void add(int u,int v,int cp,int fl)
{
	e[++cnt].u=u;e[cnt].v=v;e[cnt].cap=cp;e[cnt].flow=fl;
    nxt[cnt]=fir[u];fir[u]=cnt;
}

void bfs()
{
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    queue<int>q;
    d[t]=0;
    vis[t]=1;
    q.push(t);
    while(!q.empty())
    {
        int k=q.front();
        q.pop();
        for(int i=fir[k];i;i=nxt[i])
        {
            if(!vis[e[i].v] && e[i].cap==0)
            {
                vis[e[i].v]=1;
                d[e[i].v]=d[k]+1;
                q.push(e[i].v);
            }
        }
    }
}

int agument()
{
    int p=t;
    int ans=2147483647;
    while(p!=s)
    {
        ans=min(ans,e[par[p]].cap-e[par[p]].flow);
        p=e[par[p]].u;
    }
    p=t;
    while(p!=s)
    {
    	e[par[p]].flow+=ans;
        e[par[p]^1].flow-=ans;
        p=e[par[p]].u;
    }
    return ans;
}

int isap()
{
    memset(num,0,sizeof(num));
    int flow=0;
    for(int i=1;i<=n;i++)
	{
		num[d[i]]++;
		cur[i]=fir[i];
	}
    int p=s;
    while(d[s]<n)
    {
        if(p==t)
        {
            flow+=agument();
            p=s;
        }
        bool ok=0;
        for(int i=cur[p];i;i=nxt[i])
        {
            if(e[i].cap>e[i].flow && d[p]==d[e[i].v]+1)
            {
                ok=1;
                par[e[i].v]=i;
                cur[p]=i;
                p=e[i].v;
                break;
            }
        }
        if(!ok)
        {
            int mn=n-1;
            for(int i=fir[p];i;i=nxt[i])
            {
                if(e[i].cap>e[i].flow)mn=min(mn,d[e[i].v]);
            }
            if(--num[d[p]]==0)break;
            num[d[p]=mn+1]++;
            cur[p]=fir[p];
            if(p!=s)p=e[par[p]].u;
        }
    }
    return flow;
}

void build(int yhy)
{
	memset(nxt,0,sizeof(nxt));
    memset(fir,0,sizeof(fir));
    cnt=1;
    for(int i=1;i<=m;i++)
    {
    	add(1,1+i,yhy,0);
    	add(1+i,1,0,0);
    	add(1+2*m+i,t,yhy,0);
    	add(t,1+2*m+i,0,0);
    	for(int j=0;j<m;j++)
    	{
    		if(ss[i][j]==‘Y‘)
    		{
    			add(1+i,1+2*m+j+1,1,0);
    			add(1+2*m+j+1,i+1,0,0);
    		}
    		else
    		{
    			add(1+m+i,1+3*m+j+1,1,0);
    			add(1+3*m+j+1,1+i+m,0,0);
    		}
    	}
    	add(1+i,1+m+i,k,0);
    	add(1+m+i,1+i,0,0);
    	add(1+3*m+i,1+2*m+i,k,0);
    	add(1+2*m+i,1+3*m+i,0,0);
    }
}

int main()
{
    m=read();
	k=read();
	n=2+4*m;
	s=1;
	t=2+4*m;

	for(int i=1;i<=m;i++)
	{
		for(int j=0;j<m;j++)
		{
			cin>>ss[i][j];
		}
	}

    int l=0,r=m;
    while(l<=r)
    {
    	int mid=(l+r)/2;
    	build(mid);
    	bfs();
	    if(isap()==mid*m)
	    {
	    	l=mid+1;
	    	ans=mid;
	    }
	    else
	    {
	    	r=mid-1;
	    }
    }
    printf("%d\n",ans);
    return 0;
}

  

时间: 2024-12-23 03:54:30

BZOJ-1305: [CQOI2009]dance跳舞(最大流 增加超级源汇+分裂点+二分 水题)的相关文章

BZOJ 1305: [CQOI2009]dance跳舞( 最大流 )

云神代码很短...0 ms过的...看了代码 , 大概是贪心... orz 我不会证 数据这么小乱搞就可以了吧... ←_← 这道题网络流还是可以写的... 既然限制了最多只能和 k 个不喜欢的人dance ,  那么就把每个人拆成 a , b 两个点 . 限制完了之后 , 因为 n <= 50 , 我们可以直接从从小到大枚举 , 一个一个增广 . 具体建图 : boy_a( i ) -> boy_b( i ) ( cap : k ) , girl_b( i ) -> girl_a( i

bzoj 1305: [CQOI2009]dance跳舞

题目链接 bzoj 1305: [CQOI2009]dance跳舞 题解 男,女生拆点A1A2,B1B2,拆成两点间分别连容量为K的边,限制与不喜欢的人跳舞的数量 A1连接源点容量为x,B1连接汇点容量为x,x即为歌曲数目 对与相互喜欢的男女直在A1,B1间接连容量为1的边 对于相互不喜欢A2练到B2,容量为1 二分x的大小,每次重新构图,判断该图是否满流,慢流则说明该曲目可行 代码 #include<queue> #include<cstdio> #include<cstr

BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流

题目大意:给定n个男生和n个女生,一些互相喜欢而一些不.举行几次舞会,每次舞会要配成n对.不能有同样的组合出现.每一个人仅仅能与不喜欢的人跳k次舞,求最多举行几次舞会 将一个人拆成两个点.点1向点2连一条流量为k的边.两个人若互相喜欢则点1之间连边,不喜欢则点2之间连边 对于每个要验证的x值 将每个人的点1向源或汇连一条流量为x的边 然后二分答案跑最大流就可以 #include<cstdio> #include<cstring> #include<iostream> #

BZOJ 1305 [CQOI2009]dance跳舞(二分+网络流)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1305 [题目大意] 一次舞会有n个男孩和n个女孩. 每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞. 每个男孩都不会和同一个女孩跳两首(或更多)舞曲. 有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”). 每个男孩最多只愿意和k个不喜欢的女孩跳舞, 而每个女孩也最多只愿意和k个不喜欢的男孩跳舞.给出每对男孩女孩是否相互喜欢的信息, 舞会最多能有几首舞曲? [题解] 我们

bzoj 1305: [CQOI2009]dance 二分+網絡流判定

1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 1340  Solved: 581[Submit][Status] Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”).每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜

1305: [CQOI2009]dance跳舞

Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 4169  Solved: 1804[Submit][Status][Discuss] Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”).每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞.给出每对男孩女

【BZOJ 1305】 [CQOI2009]dance跳舞

1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 1586  Solved: 666 [Submit][Status] Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会"单向喜欢").每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只

bzoj千题计划130:bzoj1305: [CQOI2009]dance跳舞

http://www.lydsy.com/JudgeOnline/problem.php?id=1305 每个人拆为喜欢(yes)和不喜欢(no)两个点 二分答案 1.每两个人之间只能跳一次 喜欢则 男yes i 向 女yes j 连流量为1的边 不喜欢则 男no i 向 女no j 连流量为1的边 2.最多与k个不喜欢的人跳 男yes i 向 男no i 连流量为 k的边 女no j 向 女yes j 连流量为k 的边 3. 源点向 男yes i 连流量mid 的边 女yes j 向汇点连流量

bzoj1305: [CQOI2009]dance跳舞(二分答案+网络流)

1305: [CQOI2009]dance跳舞 题目:传送门 题解: 一眼网络流基础建模...然后就GG了 二分答案+拆点建边+最大流判断: 把男女生拆为男1,男2,女1,女2 1.男1和男2还有女1和女2之间连边,流量为约束条件k 2.st连男1,女2连ed,流量为二分的mid 3.如果男生i喜欢女生j,就将男1与女2相连(不在约束条件内) 4.如果不喜欢,就将男2与女1相连(在约束条件内) 代码: 1 #include<cstdio> 2 #include<cstring> 3