1 条题解
-
0
自动搬运
来自洛谷,原作者为

yybyyb
**搬运于
2025-08-24 21:45:51,当前版本为作者最后更新于2017-12-27 17:30:28,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
如果这题换个问法:能不能跳a支舞曲
我们来看看
把每个人拆成喜欢和不喜欢两个点
从S向每个男生连容量为a的边,表示限制a支舞曲
再从男生连向喜欢和不喜欢的两个点,
但是这样子没法限制,因为只说了不能和超过K个不喜欢的人跳舞
所以可以直接从S连向男生喜欢,容量为a
再从男生喜欢连向男生不喜欢连边,容量为K
这样的话就解决了这个问题
接下来就很好办了
男生喜欢连向女生喜欢
男生不喜欢连向女生不喜欢
而女生之间的连边类似于男生
(你就想,如果这个图反过来是一样的,所以怎么连边就很清晰了)
这个时候跑最大流
求出来的就是最大的匹配数
如果最大流恰好等于a*n
也就是恰好a*n组匹配,意味着可行
现在再来看这个问题
既然要求最大的a
所以就二分一下
然后每次把图重构一下流量
二分就行了
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define MAX 300 #define MAXL 100000 #define INF 1000000000 inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line { int v,next,w; }e[MAXL]; int h[MAX],cnt; int ans,S,T,n,m,K; inline void Add(int u,int v,int w) { e[cnt]=(Line){v,h[u],w}; h[u]=cnt++; e[cnt]=(Line){u,h[v],0}; h[v]=cnt++; } int level[MAX]; int cur[MAX]; bool BFS() { memset(level,0,sizeof(level)); level[S]=1; queue<int> Q; Q.push(S); while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=h[u];i!=-1;i=e[i].next) { int v=e[i].v; if(e[i].w&&!level[v]) level[v]=level[u]+1,Q.push(v); } } return level[T]; } int DFS(int u,int flow) { if(flow==0||u==T)return flow; int ret=0; for(int &i=cur[u];i!=-1;i=e[i].next) { int v=e[i].v; if(e[i].w&&level[v]==level[u]+1) { int dd=DFS(v,min(flow,e[i].w)); flow-=dd;ret+=dd; e[i].w-=dd;e[i^1].w+=dd; } } return ret; } int Dinic() { int ret=0; while(BFS()) { for(int i=S;i<=T;++i)cur[i]=h[i]; ret+=DFS(S,INF); } return ret; } char g[MAX][MAX]; void Build(int mid) { memset(h,-1,sizeof(h)); cnt=0; for(int i=1;i<=n;++i) { Add(S,i,mid); Add(i+n+n,T,mid); Add(i,i+n,K); Add(i+n+n+n,i+n+n,K); } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(g[i][j]=='Y') Add(i,j+n+n,1); else Add(i+n,j+n+n+n,1); } int main() { n=read();K=read(); S=0;T=n+n+n+n+1; for(int i=1;i<=n;++i) scanf("%s",g[i]+1); int l=0,r=n; while(l+1<r) { int mid=(l+r)>>1; Build(mid); if(Dinic()==mid*n)l=mid; else r=mid; } Build(r); printf("%d\n",Dinic()==r*n?r:l); return 0; }
- 1
信息
- ID
- 2227
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者