1. 程式人生 > >P3153 [CQOI2009]跳舞(最大流)

P3153 [CQOI2009]跳舞(最大流)

turn ont 技術分享 簡單 int () har 輸入 clas

題目描述

一次舞會有n個男孩和n個女孩。每首曲子開始時,所有男孩和女孩恰好配成n對跳交誼舞。每個男孩都不會和同一個女孩跳兩首(或更多)舞曲。有一些男孩女孩相互喜歡,而其他相互不喜歡(不會”單向喜歡“)。每個男孩最多只願意和k個不喜歡的女孩跳舞,而每個女孩也最多只願意和k個不喜歡的男孩跳舞。給出每對男孩女孩是否相互喜歡的信息,舞會最多能有幾首舞曲?

輸入輸出格式

輸入格式:

第一行包含兩個整數n和k。以下n行每行包含n個字符,其中第i行第j個字符為‘Y‘當且僅當男孩i和女孩j相互喜歡。

輸出格式:

僅一個數,即舞曲數目的最大值。

輸入輸出樣例

輸入樣例#1: 復制
3 0
YYY
YYY
YYY
輸出樣例#1: 復制
3

說明

N<=50 K<=30






開始的時候想網絡流的方向考慮了,但是不知道怎麽建模,

然後以為是二分圖,就打了一發二分圖,水了82分 qwq,然後就知道這題不簡單qwq

看了一波題解,發現原來時神仙題啊

圖片轉載自:https://blog.csdn.net/xu0_zy/article/details/80887701

技術分享圖片

註意的點,k限制了和k個不喜歡的女孩 和 女孩個k個不喜歡的男孩配對

然後出現了一個問題,一開始把S點所有的男孩連邊,T和所有的女孩連邊,但是邊的流量是多少呢?inf嗎?然後最大流/4 ? 其實是不對的,題目要求每次跳舞n的人都得有舞伴,若果這樣的話,有可能會出現,其余的男孩貢獻的n的流量,但是有一個男孩貢獻了n+1的流量,也就是說最後一跳舞只有一對,

解決的方法就是,二分或者枚舉最大的數目,S向每個男孩的容量都是mid ,如果最後的最大流是mid*n,就說明mid這個數目是可行的。

邊權是一代表只能向他來一次

拆點後點之間的容量1代表這個點只能經過一次






  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<set
> 8 #include<map> 9 #include<vector> 10 #include<queue> 11 using namespace std; 12 #define MAX 300 13 #define MAXL 100000 14 #define INF 1000000000 15 inline int read() 16 { 17 int x=0,t=1;char ch=getchar(); 18 while((ch<0||ch>9)&&ch!=-)ch=getchar(); 19 if(ch==-)t=-1,ch=getchar(); 20 while(ch<=9&&ch>=0)x=x*10+ch-48,ch=getchar(); 21 return x*t; 22 } 23 struct Line 24 { 25 int v,next,w; 26 }e[MAXL]; 27 int h[MAX],cnt; 28 int ans,S,T,n,m,K; 29 inline void Add(int u,int v,int w) 30 { 31 e[cnt]=(Line){v,h[u],w}; 32 h[u]=cnt++; 33 e[cnt]=(Line){u,h[v],0}; 34 h[v]=cnt++; 35 } 36 int level[MAX]; 37 int cur[MAX]; 38 bool BFS() 39 { 40 memset(level,0,sizeof(level)); 41 level[S]=1; 42 queue<int> Q; 43 Q.push(S); 44 while(!Q.empty()) 45 { 46 int u=Q.front();Q.pop(); 47 for(int i=h[u];i!=-1;i=e[i].next) 48 { 49 int v=e[i].v; 50 if(e[i].w&&!level[v]) 51 level[v]=level[u]+1,Q.push(v); 52 } 53 } 54 return level[T]; 55 } 56 int DFS(int u,int flow) 57 { 58 if(flow==0||u==T)return flow; 59 int ret=0; 60 for(int &i=cur[u];i!=-1;i=e[i].next) 61 { 62 int v=e[i].v; 63 if(e[i].w&&level[v]==level[u]+1) 64 { 65 int dd=DFS(v,min(flow,e[i].w)); 66 flow-=dd;ret+=dd; 67 e[i].w-=dd;e[i^1].w+=dd; 68 } 69 } 70 return ret; 71 } 72 int Dinic() 73 { 74 int ret=0; 75 while(BFS()) 76 { 77 for(int i=S;i<=T;++i)cur[i]=h[i]; 78 ret+=DFS(S,INF); 79 } 80 return ret; 81 } 82 char g[MAX][MAX]; 83 void Build(int mid) 84 { 85 memset(h,-1,sizeof(h)); 86 cnt=0; 87 for(int i=1;i<=n;++i) 88 { 89 Add(S,i,mid); 90 Add(i+n+n,T,mid); 91 Add(i,i+n,K); 92 Add(i+n+n+n,i+n+n,K); 93 } 94 for(int i=1;i<=n;++i) 95 for(int j=1;j<=n;++j) 96 if(g[i][j]==Y) 97 Add(i,j+n+n,1); 98 else 99 Add(i+n,j+n+n+n,1); 100 } 101 int main() 102 { 103 n=read();K=read(); 104 S=0;T=n+n+n+n+1; 105 for(int i=1;i<=n;++i) 106 scanf("%s",g[i]+1); 107 int l=0,r=n; 108 while(l+1<r) 109 { 110 int mid=(l+r)>>1; 111 Build(mid); 112 if(Dinic()==mid*n)l=mid; 113 else r=mid; 114 } 115 Build(r); 116 printf("%d\n",Dinic()==r*n?r:l); 117 return 0; 118 }

P3153 [CQOI2009]跳舞(最大流)