一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为‘Y‘当且仅当男孩i和女孩j相互喜欢。
仅一个数,即舞曲数目的最大值。
N<=50 K<=30
二分/枚举+网络流
我是用枚举歌曲数为x来做的(枚举每次只要把一些边的流量+1,在原图上继续增广;而二分需要重新构图,重新增广)
我把每个人拆成了3个点a,b,c:a是总点,b是喜欢点,c是不喜欢点。
如果男生i喜欢女生j,则ib,jb连流量为1的边;如果不喜欢则ic,jc连流量为1的边。
对于每个男生的a点与s连流量为x的边,女生的a点与t连流量为x的。
每个人的a与b之间连流量为n的边,a与c之间连流量为k的边。
直接跑最大流,看是否满流,不满流则输出结果。
其实这道题的a点和b点可以合并成一个点的。。
0ms的贪心做法是错误的:
3 0
YYY
YNN
YNN这组数据答案为0,贪心跑出来是1。
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cstdlib> #include <queue> #define M 1005 #define inf 0x3f3f3f3f using namespace std; char st[100]; int h[M],flow,cur[M],v[M],d[M],s,t,n,k,tot=1; struct edge { int from,to,cap,flow,ne; }E[M*200]; void Addedge(int from,int to,int cap) { E[++tot]=(edge){from,to,cap,0,h[from]}; h[from]=tot; E[++tot]=(edge){to,from,0,0,h[to]}; h[to]=tot; } bool bfs() { queue<int> q; q.push(s); memset(v,0,sizeof(v)); v[s]=1,d[s]=0; while (!q.empty()) { int x=q.front(); q.pop(); for (int i=h[x];i;i=E[i].ne) { edge e=E[i]; if (!v[e.to]&&e.cap>e.flow) { v[e.to]=1; q.push(e.to); d[e.to]=d[x]+1; } } } return v[t]; } int dfs(int x,int a) { int flow=0; if (x==t||!a) return a; for (int &i=cur[x];i;i=E[i].ne) { edge &e=E[i]; if (d[e.to]!=d[x]+1) continue; int f=dfs(e.to,min(e.cap-e.flow,a)); if (f>0) { e.flow+=f; E[i^1].flow-=f; flow+=f; a-=f; if (!a) break; } } return flow; } void dinic() { while (bfs()) { for (int i=s;i<=t;i++) cur[i]=h[i]; flow+=dfs(s,inf); } } int main() { scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) { scanf("%s",st); for (int k=0;k<n;k++) { int j=k+1; if (st[k]=='Y') Addedge(2*n+i,3*n+j,1); else Addedge(4*n+i,5*n+j,1); } } s=0,t=6*n+1; for (int i=1;i<=n;i++) Addedge(i,4*n+i,k),Addedge(5*n+i,n+i,k), Addedge(i,2*n+i,n),Addedge(3*n+i,n+i,n); int be=0; for (int i=1;i<=n;i++) { if (i==1) be=tot+1; Addedge(s,i,0); Addedge(n+i,t,0); } int ans=0; flow=0; while (1) { for (int i=be;i<=tot;i+=2) E[i].cap++; dinic(); if (flow==(ans+1)*n) ans++; else break; } printf("%d\n",ans); return 0; }
感悟:
一开始建图的+-写错了,wa好多次。。
原文地址:http://blog.csdn.net/regina8023/article/details/44008193