BZOJ 1305: [CQOI2009]dance跳舞

这是前天做的一道题。。今天补发一下。。

还是网络流,关键在于图怎么建

把每个人拆成两个点,如果男孩 i 喜欢女孩 j ,则连接点a1i和 b1j,流量为1;

如果不喜欢,则连接a2i 和 b2j,流量为1;

然后一步是关键,因为每个人都不能和不喜欢的人跳多于K支舞,

所以把a1i 和 a2i 连起来,流量为K;b2i 和b1i 连起来,流量为K(注意方向)

然后把源点和a1 各点连起来,b1各点和汇点连起来,流量为mx;

符合条件的mx 的最大值就是答案了(每个人都跳了mx支舞)

怎么判断mx是否符合条件呢?

当每个人都跳了mx支舞,即网络的流量ans==mx * n就行了

所以二分答案,再判断可行性就行了

坑爹的BZOJ输入数据行末有空格害得我WA了好几次查错又查不出T_T

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 1100
#define maxe 500100
#define g getchar()
#define inf 0x3f3f3f3f

using namespace std;
struct re{int v,fl,next;}ed[maxe];
int e,n,k,answer;
int head[maxn],pd[maxn],dui[maxe];
char ch;
bool map[100][100];
inline void ins(int x,int y,int w){
	ed[++e].v=y;ed[e].fl=w;ed[e].next=head[x];head[x]=e;
	
	ed[++e].v=x;ed[e].fl=0;ed[e].next=head[y];head[y]=e;
}
inline int min(int x,int y){
	return x<y?x:y;
}
void init(){
	scanf("%d%d",&n,&k);
	memset(map,0,sizeof(map));
	for(int i=1;i<=n;++i){
		char ch[51];
		scanf("%s",ch);
		for(int j=1;j<=n;j++)
		if(ch[j-1]=='Y')map[i][j]=1;
    }
}
void makemap(int w){                        //建图
	e=0;
	memset(head,0,sizeof(head));
	for(int i=1;i<=n;++i){
		ins(0,i,w);
		ins(i,i+n,k);
		ins(3*n+i,2*n+i,k);
		ins(2*n+i,4*n+1,w);
		for(int j=1;j<=n;++j)
		if(map[i][j])ins(i,n*2+j,1);else ins(i+n,n*3+j,1);
	}
}
bool bfs(){
	int tou=1,wei=1;
	memset(pd,-1,sizeof(pd));
	dui[1]=0;pd[0]=0;
	for(;tou<=wei;++tou){
		int u=dui[tou];
		for(int i=head[u];i;i=ed[i].next){
			if(ed[i].fl&&pd[ed[i].v]<0){
				pd[ed[i].v]=pd[u]+1;
				dui[++wei]=ed[i].v;
			}
		}
	}
	return pd[4*n+1]!=-1;
}
int dfs(int x,int w){
	if(x==4*n+1)return w;
	int le,used=0;
	for(int i=head[x];i;i=ed[i].next){
		if(pd[ed[i].v]==pd[x]+1&&ed[i].fl){
			le=w-used;
			le=dfs(ed[i].v,min(le,ed[i].fl));
			used+=le;
			ed[i].fl-=le;
			ed[i%2?i+1:i-1].fl+=le;
			if(used==w)return w;
		}
	}
	if(!used)pd[x]=-1;
	return used;
}
void work(){                                    //二分答案
	int l=0,r=50,mid;
	while(l<=r){
		mid=(l+r)>>1;
		makemap(mid);
		int ans=0;
		while(bfs())ans+=dfs(0,inf);
		if(ans==n*mid){
			answer=mid;l=mid+1;
		}
		else r=mid-1;
		
	}
}
int main(){
	init();
	work();
	printf("%d\n",answer);
	return 0;
}

类似的网络流 戳这儿

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值