[ C Q O I 2009 ] d a n c e 跳 舞 [CQOI2009]dance跳舞 [CQOI2009]dance跳舞
Description:
- 一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
Input Format:
- 第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为’Y’当且仅当男孩i和女孩j相互喜欢。
Output Format:
- 仅一个数,即舞曲数目的最大值。
Sample Input:
- 3 0
YYY
YYY
YYY
Sample Output:
- 3
TJ:
二分图匹配
每次找图中的最大匹配
匹配数等于n时答案+1,然后把当前匹配的边全删去继续二分图匹配。
匹配不到n就跳出,最后答案为min(ans + k, n)
考虑每次匹配,此次匹配的方案和下次能否构成最大匹配没有影响,假设此次匹配中
A->A’
B->B’
改成
A->B’
B->A’
那么下次匹配时还是可以匹配A和B
所以当前选择的匹配和下一次能否构成最大匹配无影响
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 55;
char s[MAXN];
int n,k,G[MAXN][MAXN],match[MAXN],vis[MAXN];
bool dfs(int u){
vis[u] = 1;
for(int i = 1; i <= n; i++){
if(!G[u][i]) continue;
if(match[i]==-1||(!vis[match[i]]&&dfs(match[i]))){
match[i] = u;
return true;
}
}
return false;
}
int BMatch(){
int tot = 0;
memset(match,-1,sizeof(match));
for(int i = 1; i <= n; i++){
memset(vis,0,sizeof(vis));
if(dfs(i)) tot++;
}
return tot;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1305/10.in","r",stdin);
#endif
memset(G,0,sizeof(G));
scanf("%d %d",&n,&k);
for(int i = 1; i <= n; i++) {
scanf("%s",s+1);
for(int j = 1; j <= n; j++) G[i][j] = s[j]=='Y';
}
int ans = 0;
while(true){
int tp = BMatch();
if(tp==n) ans++;
else break;
for(int i = 1; i <= n; i++) G[match[i]][i] = 0;
}
ans = min(n,ans+k);
printf("%d\n",ans);
#ifndef ONLINE_JUDGE
freopen("1305/10.out","r",stdin);
scanf("%d",&ans);
printf("%d\n",ans);
#endif
return 0;
}
网络流拆点
#include<bits/stdc++.h>
using namespace std;
#define S 0
#define T n*6+1
const int INF = 0x3f3f3f3f;
const int MAXN = 111;
struct EDGE{
int to,cap,rev;
EDGE(){}
EDGE(int to,int cap,int rev){
this->to = to;
this->cap = cap;
this->rev = rev;
}
};
int n,k,rk[MAXN<<2],iter[MAXN<<2];
int mp[MAXN][MAXN];
vector<EDGE> G[MAXN<<2];
char s[MAXN];
void Add_edge(int u,int v,int cap){
G[u].push_back(EDGE(v,cap,(int)G[v].size()));
G[v].push_back(EDGE(u,0,(int)G[u].size()-1));
}
void init(){ for(int i = 0; i < (MAXN<<2); i++) G[i].clear(); }
void rebuild(int m){
for(int i = 1; i <= n; i++){
Add_edge(S,i,m);
Add_edge(i,i+n*2,INF);
Add_edge(i,i+n*4,k);
}
for(int i = n + 1; i <= n*2 ;i++){
Add_edge(i,T,m);
Add_edge(i+n*2,i,INF);
Add_edge(i+n*4,i,k);
}
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) {
if(mp[i][j]) Add_edge(i+n*2,j+n*3,1);
else Add_edge(i+n*4,j+n*5,1);
}
}
bool BFS(){
memset(iter,0,sizeof(iter));
memset(rk,0,sizeof(rk));
rk[S] = 1;
queue<int> que;
que.push(S);
while(!que.empty()){
int now = que.front();
que.pop();
for(int i = 0; i <(int)G[now].size(); i++){
EDGE e = G[now][i];
if(!e.cap||rk[e.to]) continue;
rk[e.to] = rk[now] + 1;
que.push(e.to);
}
}
return rk[T]!=0;
}
int DFS(int u,int f){
if(u==T) return f;
for(int i = 0; i < (int)G[u].size(); i++){
EDGE &e = G[u][i];
if(!e.cap||rk[e.to]!=rk[u]+1) continue;
int d = DFS(e.to,min(f,e.cap));
if(d){
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
return 0;
}
int Dinic(){
int flow = 0;
while(BFS()){
int d = DFS(S,INF);
while(d){
flow+=d;
d = DFS(S,INF);
}
}
return flow;
}
bool check(int m){
init();
rebuild(m);
return Dinic()==m*n;
}
int pan(){
int l = k,r = n;
while(l<=r){
int m = (l+r)>>1;
if(check(m)) l = m + 1;
else r = m - 1;
}
return r;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1305/6.in","r",stdin);
#endif
scanf("%d %d",&n,&k);
for(int i = 1; i <= n; i++){
scanf("%s", s+1);
for(int j = 1; j <= n; j++){
if(s[j]=='Y') mp[i][j] = 1;
else mp[i][j] = 0;
}
}
printf("%d\n",pan());
#ifndef ONLINE_JUDGE
freopen("1305/6.out","r",stdin);
int x;
scanf("%d",&x);
printf("%d\n",x);
#endif
return 0;
}
``