跟隨YveH的腳步又做了道網路流。。。%%%
1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MB
Submit: 2119 Solved: 878
[Submit][Status][Discuss]
Description
一次舞會有n個男孩和n個女孩。每首曲子開始時,所有男孩和女孩恰好配成n對跳交誼舞。每個男孩都不會和同一個女孩跳兩首(或更多)舞曲。有一些男孩女孩相互喜歡,而其他相互不喜歡(不會“單向喜歡”)。每個男孩最多隻願意和k個不喜歡的女孩跳舞,而每個女孩也最多隻願意和k個不喜歡的男孩跳舞。給出每對男孩女孩是否相互喜歡的資訊,舞會最多能有幾首舞曲?
Input
第一行包含兩個整數n和k。以下n行每行包含n個字元,其中第i行第j個字元為’Y’當且僅當男孩i和女孩j相互喜歡。
Output
僅一個數,即舞曲數目的最大值。
Sample Input
3 0
YYY
YYY
YYY
Sample Output
3
HINT
N<=50 K<=30
Source
加強資料By dwellings and liyizhen2
這道題,網上有說可以貪心的,然而似乎被證明是錯誤的了,(反正我也想不出貪心策略)
說一下建圖:(建圖有點麻煩,多謝恆妹的查錯)
每個男孩建立兩個次節點,每個女孩建立兩個次節點,分別處理喜歡的和不喜歡的
超級源S向所有男生主節點連邊,所有女生向超級匯連邊,邊權為二分列舉出來的值
男生主節點和處理喜歡的男生次節點連邊邊權為INF,向處理不喜歡的男生連邊邊權為k
女生處理喜歡的次節點向主節點連邊,邊權INF;處理不喜歡的次節點與主節點相連邊權為k
相互喜歡的男生女生的喜歡節點相連邊權為1,相互不喜歡的連邊,邊權為1
二分答案,及超級源指向男生主節點的邊權(女生主節點指向超級匯的邊權)
每次二分出答案重新建圖,跑一邊Dinic判斷是否滿流,最後輸出二分出邊權即可。
(這道題目不錯不錯)
(一開始沒寫二分寫了個列舉,結果卡常了。。。“竟然被卡常了,666啊”—by YveH)
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int q[3000],h,t;
struct data{
int to,next,v;
}edge[1000001];
int cnt;
int head[3000]={0};
int dis[3000]={0};
int xh[51][51];
int n,k,num;
void add(int u,int v,int w)
{
cnt++;
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
edge[cnt].v=w;
}
void init()
{
scanf("%d%d",&n,&k);
for (int i=1; i<=n; i++)
{
char x[51];
scanf("%s",&x);
for (int j=1; j<=n; j++)
if (x[j-1]=='Y')
xh[i][j]=1;
}
}
void make(int v)
{
//男生i的主點序號為 in 則處理喜歡的次點序號為in+1,處理不喜歡的次點序號為in+2
//女生同理,接男生後面排
//超級源的序號0,超級匯為2*n*3+1
cnt=1; memset(head,0,sizeof(head));
num=1;
for (int i=1; i<=n; i++)
{
add(0,num,v);add(num,0,0);
num++;
add(num-1,num,0x7fffffff);add(num,num-1,0);
num++;
add(num-2,num,k);add(num,num-2,0);
num++;
}
for (int i=1; i<=n; i++)
{
add(num,2*n*3+1,v);add(2*n*3+1,num,0);
num++;
add(num,num-1,0x7fffffff);add(num-1,num,0);
num++;
add(num,num-2,k);add(num-2,num,0);
num++;
}
for (int i=1; i<=n; i++)
{
for (int j=1; j<=n; j++)
{
if (xh[i][j]==1)
{
add(i*3-2+1,3*n+j*3-2+1,1);
add(3*n+j*3-2+1,i*3-2+1,0);
}
else
{
add(i*3-2+2,3*n+j*3-2+2,1);
add(3*n+j*3-2+2,i*3-2+2,0);
}
}
}
}
bool bfs()
{
memset(dis,-1,sizeof(dis));
q[1]=0; dis[0]=1;
h=0; t=1;
while (h<t)
{
int j=q[++h],i=head[j];
while (i)
{
if (edge[i].v>0 && dis[edge[i].to]<0)
{
dis[edge[i].to]=dis[j]+1;
q[++t]=edge[i].to;
}
i=edge[i].next;
}
}
if (dis[num]>0)
return true;
else
return false;
}
int dfs(int loc,int low)
{
int now=0;
if (loc==num) return low;
int i=head[loc];
while (i)
{
if (edge[i].v>0 && dis[edge[i].to]==dis[loc]+1 && (now=dfs(edge[i].to,min(edge[i].v,low))))
{
edge[i].v-=now;
edge[i^1].v+=now;
return now;
}
i=edge[i].next;
}
return 0;
}
int main()
{
init();
int ans;
int flow;
int l=0,r=50;
while (l<=r)
{
int mid=(l+r)>>1;
make(mid);
flow=0;
while (bfs())
{
int now=0;
while ((now=dfs(0,0x7fffffff)))
flow+=now;
}
if (mid*n<=flow)
{l=mid+1;ans=mid;}
else
r=mid-1;
}//二分判斷是否滿流
printf("%d",ans);
return 0;
}