题目大意
有n个男孩和n个女孩,男女间要么互相喜欢要么不喜欢,跳一次舞每个人和没跳过的喜欢的跳或和最多k个不喜欢的跳。求最多跳几次。
解题思路
有一个直观的贪心,最大的答案为每个人喜欢的人数取最小值后加k,但我们能不能保证有合法解呢,反正bzoj上能过,但某个oj上不能过。
于是就打了网络流,先二分一个答案,每个人拆成两个点(和喜欢的人跳与和不喜欢的人跳),源到和喜欢的人跳流量为ans,和喜欢的人跳到和不喜欢的人跳流量为k,每个男女流量为1。
code
贪心(正确性可能有问题)
#include
#include
#include
#include
#include
#define LF double
#define LL long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a>b)?b:a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=50000;
int n,K,a[maxn+10],b[maxn+10];
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d\n",&n,&K);
fo(i,1,n){
fo(j,1,n){
char ch;scanf("%c",&ch);
if(ch=='Y')a[i]++,b[j]++;
}
scanf("\n");
}
int ans=n;
fo(i,1,n)ans=min(ans,min(a[i]+K,b[i]+K));
printf("%d",ans);
return 0;
}
正解
using namespace std;
int const maxn=50,inf=2147483647;
int n,K,gra,to[maxn*8+maxn*maxn*2+10],size[maxn*8+maxn*maxn*2+10],cost[maxn*8+maxn*maxn*2+10],next[maxn*8+maxn*maxn*2+10],begin[maxn*4+10],dis[maxn*4+10];
bool map[maxn+10][maxn+10],done[maxn*4+10];
void insert(int u,int v,int s){
to[gra]=v;
size[gra]=s;
cost[gra]=1;
next[gra]=begin[u];
begin[u]=gra++;
to[gra]=u;
size[gra]=0;
cost[gra]=-1;
next[gra]=begin[v];
begin[v]=gra++;
}
int addflow(int now,int t,int flow){
done[now]=1;
if(now==t)return flow;
for(int i=begin[now],add;i;i=next[i])
if(size[i]&&(!done[to[i]])&&(dis[now]==dis[to[i]]+cost[i])&&(add=addflow(to[i],t,min(flow,size[i])))){
size[i]-=add;
size[i^1]+=add;
return add;
}
return 0;
}
bool updis(int s,int t){
int add=inf;
fo(i,s,t)
if(done[i])
for(int j=begin[i];j;j=next[j])
if(size[j]&&(!done[to[j]]))
add=min(add,dis[to[j]]+cost[j]-dis[i]);
if(add==inf)return 0;
fo(i,s,t)
if(done[i])dis[i]+=add;
return 1;
}
int maxflow(int s,int t){
int ans=0;
do{
memset(done,0,sizeof(done));
for(int add;add=addflow(s,t,inf);){
ans+=add;
memset(done,0,sizeof(done));
}
}while(updis(s,t));
return ans;
}
bool check(int ans){
gra=2;memset(begin,0,sizeof(begin));
fo(i,1,n)insert(0,i,ans),insert(i,i+n,K),insert(i+n*2,i+n*3,K),insert(i+n*3,n*4+1,ans);
fo(i,1,n)
fo(j,1,n)
if(map[i][j])insert(i,j+n*3,1);
else insert(i+n,j+n*2,1);
return ans*n==maxflow(0,n*4+1);
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d\n",&n,&K);
fo(i,1,n){
fo(j,1,n){
char ch;scanf("%c",&ch);
if(ch=='Y')map[i][j]=1;
}
scanf("\n");
}
int l=0,r=n;
for(;l!=r;){
int m=(l+r+1)/2;
if(check(m))l=m;
else r=m-1;
}
printf("%d",l);
return 0;
}