• [BZOJ1305/Luogu3153][CQOI2009]dance跳舞


    题目链接:

    BZOJ1305

    Luogu3153

    看见匹配就上网络流

    二分答案(Mat),把每个人拆成喜欢和不喜欢两个点。

    对于男生,从源点向喜欢点连边,容量为(Mat),同时在喜欢和不喜欢之间连边,容量为(k)(因为总共只跳(Mat)次舞,要把两个点限制在一起)。

    对于女生也是类似的反着,不喜欢( ightarrow)喜欢,容量为(k),喜欢( ightarrow)汇点,容量为(Mat)

    然后对于两个人((x,y)),若(x)喜欢(y),在对于喜欢的点之间,容量为(1),否则连不喜欢。

    然后用了个(ISAP)

    #include <cstdio>
    #include <cstring>
    
    inline int Min(int a,int b){return a<b?a:b;}
    
    int n,k,St,Ed;
    int Head[205],Next[40005],To[40005],Val[40005],En;
    int Dis[205],Pre[205],Cur[205],Cnt[205];
    char Suki[55][55];
    
    inline void Add(int x,int y,int z)
    {
    	Next[++En]=Head[x],To[Head[x]=En]=y,Val[En]=z;
    	Next[++En]=Head[y],To[Head[y]=En]=x,Val[En]=0;
    }
    
    int Augment()
    {
    	int Res=0x3f3f3f3f;
    	for(int x=Ed;x!=St;x=To[Pre[x]^1])Res=Min(Res,Val[Pre[x]]);
    	for(int x=Ed,i;x!=St;x=To[i^1])Val[i=Pre[x]]-=Res,Val[i^1]+=Res;
    	return Res;
    }
    
    int ISAP()
    {
    	memset(Dis,0,sizeof Dis);
    	memcpy(Cur,Head,sizeof Cur);
    	memset(Cnt,0,sizeof Cnt);
    	Cnt[0]=Ed;
    	int Flow=0,x=St;
    	while(Dis[St]<Ed)
    	{
    		if(x==Ed)Flow+=Augment(),x=St;
    		bool Flag=false;
    		for(int i=Cur[x],y;i;i=Next[i])
    			if(Val[i]&&Dis[y=To[i]]+1==Dis[x])
    				Flag=true,Cur[x]=Pre[y]=i,x=y,i=0;
    		if(Flag)continue;
    		int Wd=Ed-1;
    		for(int i=Head[x];i;i=Next[i])
    			if(Val[i])Wd=Min(Wd,Dis[To[i]]);
    		if(!--Cnt[Dis[x]])break;
    		++Cnt[Dis[x]=Wd+1],Cur[x]=Head[x];
    		if(x!=St)x=To[Pre[x]^1];
    	}
    	return Flow;
    }
    
    void Build(int Tar)
    {
    	memset(Head,0,sizeof Head),En=1;
    	St=n<<2|1,Ed=St+1;//源点汇点
    	for(int i=1;i<=n;++i)
    	{//[1,n]男生喜欢,[n+1,n*2]男生不喜欢
    		Add(St,i,Tar),Add(i,n+i,k);
    		Add((n<<1)+i,Ed,Tar),Add(n*3+i,(n<<1)+i,k);
    	}//[n*2+1,n*3]女生喜欢,[n*3+1,n*4]女生不喜欢
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			if(Suki[i][j]=='Y')
    				Add(i,(n<<1)+j,1);
    			else
    				Add(n+i,n*3+j,1);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;++i)scanf("%s",Suki[i]+1);
    	int l=0,r=n+1;
    	while(l<r)
    	{
    		int Mid=(l+r)>>1;
    		Build(Mid);
    		if(ISAP()==n*Mid)l=Mid+1;
    		else r=Mid;
    	}
    	printf("%d
    ",l-1);
    	return 0;
    }
    
  • 相关阅读:
    css清除浮动
    vue在v-for循环中绑定v-model
    Element UI 数字输入框组件添加鼠标滚动事件
    vue-cli搭建vue开发环境
    vue组件通信
    H5新增的postMessage跨域解决方案Demo
    零碎方法笔记
    django中操作cookie与session
    python中装饰器修复技术
    django中orm的批量操作
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/10200438.html
Copyright © 2020-2023  润新知