zoukankan      html  css  js  c++  java
  • BZOJ1305 [CQOI2009]dance跳舞 【网络流】

    1305: [CQOI2009]dance跳舞

    Time Limit: 5 Sec  Memory Limit: 162 MB
    Submit: 3714  Solved: 1572
    [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


    匹配问题,用网络流解决

    将每个人拆开成喜欢和不喜欢,分别连边,然后二分向源汇点连边的容量,每次看看是否能满载

    具体【我们假设x是喜欢,y是不喜欢,i是男孩,j是女孩】:

    ①男孩i与女孩j相互喜欢,xi->xj,容量1

    ②男孩i与女孩j不喜欢,yi->yj,容量1

    ③xi->yi,容量K

    ④yj->xj,容量K

    二分容量w

    ⑤S->xi,容量w

    ⑥xj->T,容量w

    每次跑一次最大流看看能够满载即w * N,能说明可以跳至少w次舞

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 605,maxm = 1000005,INF = 1000000000;
    inline int RD(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    	return out * flag;
    }
    char s[55][55];
    int N,K,S,T,head[maxn],d[maxn],vis[maxn],nedge = 0,cur[maxn];
    struct EDGE{int to,f,next;}edge[maxm];
    inline void build(int u,int v,int w){
    	edge[nedge] = (EDGE){v,w,head[u]}; head[u] = nedge++;
    	edge[nedge] = (EDGE){u,0,head[v]}; head[v] = nedge++;
    }
    bool bfs(){
    	memset(vis,0,sizeof(vis));
    	queue<int> q; int u,to;
    	q.push(S); vis[S] = true;
    	while (!q.empty()){
    		u = q.front(); q.pop();
    		Redge(u) if (edge[k].f && !vis[to = edge[k].to]){
    			d[to] = d[u] + 1; vis[to] = true; q.push(to);
    		}
    	}
    	return vis[T];
    }
    int dfs(int u,int minf){
    	if (u == T || !minf) return minf;
    	int flow = 0,f,to;
    	if (cur[u] == -2) cur[u] = head[u];
    	for (int& k = cur[u]; k != -1; k = edge[k].next)
    		if (d[to = edge[k].to] == d[u] + 1 && (f = dfs(to,min(minf,edge[k].f)))){
    			edge[k].f -= f; edge[k ^ 1].f += f;
    			flow += f; minf -= f;
    			if (!minf) break;
    		}
    	return flow;
    }
    int maxflow(){
    	int flow = 0;
    	while (bfs()){
    		fill(cur,cur + maxn,-2);
    		flow += dfs(S,INF);
    	}
    	return flow;
    }
    bool check(int w){
    	nedge = 0; memset(head,-1,sizeof(head));
    	REP(i,N) build(S,i,w),build(i,i + N,K),build(i + 3 * N,i + 2 * N,K);
    	REP(i,N) REP(j,N)
    		if (s[i][j] == 'Y') build(i,j + 2 * N,1);
    		else build(i + N,j + 3 * N,1);
    	REP(i,N) build(i + 2 * N,T,w);
    	return maxflow() >= w * N;
    }
    int main(){
    	scanf("%d%d",&N,&K); S = 0; T = 4 * N + 1;
    	REP(i,N) scanf("%s",s[i] + 1);
    	int L = 0,R = N,mid;
    	while (L < R){
    		mid = L + R + 1 >> 1;
    		if (check(mid)) L = mid;
    		else R = mid - 1;
    	}
    	cout<<L<<endl;
    	return 0;
    }
    


  • 相关阅读:
    JavaScript中的事件循环
    CSS布局
    Tomcat相关
    C#参数中ref和out的区别
    angular启动4200端口后,如何停止监听4200端口
    表联接(交叉连接,内联,外联)
    如何使用vs自带的反编译工具Lldasm
    软件架构需要注意的几点,待补充。。。
    SqlServer中With(NOLOCK)
    TypeScript preview
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282761.html
Copyright © 2011-2022 走看看