首页 > 其他分享 >HDU 3277 Marriage Match III(并查集+二分+最大流)

HDU 3277 Marriage Match III(并查集+二分+最大流)

时间:2023-06-12 14:34:41浏览次数:34  
标签:HDU int 查集 flow 3277 女孩 maxn girl include


题意:和HDU3081一样的题意,只不过多了一个条件,每个女孩除了能选自己喜欢的男生之外,还能选不超过K个自己不喜欢的男生,问游戏最多能进行几轮

思路:除了选喜欢的,还能选任意K个不喜欢的,怎么建图呢?一开始我想每个女孩连喜欢的男孩,而且选K个不喜欢的男孩也连边,可是这K个要怎么确定呢?这种显然是行不通的,然后我想每个女孩和不喜欢的男孩连边,男孩和汇点连一条容量为K的边,那么其实也显然不对了。建图思路很巧妙,将每个女孩拆成两个点,中间连一条容量为K的边

           假设当前我们二分轮数为limit, 源点s编号0,女孩i分成两个点i和i+n编号(编号i的点用来连接该女孩喜欢的男孩,编号为i+n的点用来连接该女孩不喜欢的男孩), 男孩编号为2n+1到2n+n, 汇点t编号为3n+1.

           首先源点s到第i个女孩有边(s, i, limit)

           第i个女孩的i点到i+n点有边(i, i+n, k)

           如果第i个女孩可以选男孩j,那么有边(i, j, 1). 否则有边(i+n, j, 1)

           每个男孩j到汇点t有边(j, t, limit)

           最终看max_flow 是否== limit*n 即可.

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 250*3+10
#define INF 1<<29
#define LL long long
int cas=1,T;
struct Edge
{
	int from,to,cap,flow;
	Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
int n,m;
struct Dinic
{
//	int n,m;
    int s,t;
	vector<Edge>edges;        //边数的两倍
	vector<int> G[maxn];      //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
	bool vis[maxn];           //BFS使用
	int d[maxn];              //从起点到i的距离
	int cur[maxn];            //当前弧下标
	void init()
	{
	   for (int i=0;i<=n*3+1;i++)
		   G[i].clear();
	   edges.clear();
	}
	void AddEdge(int from,int to,int cap)
	{
		edges.push_back(Edge(from,to,cap,0));
		edges.push_back(Edge(to,from,0,0));        //反向弧
		int mm=edges.size();
		G[from].push_back(mm-2);
		G[to].push_back(mm-1);
	}
	bool BFS()
	{
		memset(vis,0,sizeof(vis));
		queue<int>q;
		q.push(s);
		d[s]=0;
		vis[s]=1;
		while (!q.empty())
		{
			int x = q.front();q.pop();
			for (int i = 0;i<G[x].size();i++)
			{
				Edge &e = edges[G[x][i]];
				if (!vis[e.to] && e.cap > e.flow)
				{
					vis[e.to]=1;
					d[e.to] = d[x]+1;
					q.push(e.to);
				}
			}
		}
		return vis[t];
	}

	int DFS(int x,int a)
	{
		if (x==t || a==0)
			return a;
		int flow = 0,f;
		for(int &i=cur[x];i<G[x].size();i++)
		{
			Edge &e = edges[G[x][i]];
			if (d[x]+1 == d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0)
			{
				e.flow+=f;
				edges[G[x][i]^1].flow-=f;
				flow+=f;
				a-=f;
				if (a==0)
					break;
			}
		}
		return flow;
	}

	int Maxflow(int s,int t)
	{
		this->s=s;
		this->t=t;
		int flow = 0;
		while (BFS())
		{
			memset(cur,0,sizeof(cur));
			flow+=DFS(s,INF);
		}
		return flow;
	}
}dc;
int pre[maxn];
int dis[maxn][maxn];
int Find(int x)
{
	return pre[x]==-1?x:pre[x]=Find(pre[x]);
}

bool solve(int t,int k)
{
	dc.init();
	for (int i = 1;i<=n;i++)
	{
		dc.AddEdge(0,i,t);             //每个女孩i'和源点连边
		dc.AddEdge(i,i+n,k);           //女孩的两个拆点连一条容量为k的边
		dc.AddEdge(n*2+i,n*3+1,t);     //每个男孩和汇点n*3+1连边
		for (int j = 1;j<=n;j++)
		  if (dis[i][j])
			  dc.AddEdge(i,n*2+j,1);   //女孩i'和喜欢的男孩连边,容量为1
		  else
			  dc.AddEdge(i+n,n*2+j,1);         //女孩i''和不喜欢的男孩连边,容量为1
	}
	return dc.Maxflow(0,n*3+1)==t*n;
}
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		int f,kk;
		memset(dis,0,sizeof(dis));
		memset(pre,-1,sizeof(pre));
		scanf("%d%d%d%d",&n,&m,&kk,&f);
        for (int i = 1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			dis[u][v]=1;
		}
		for (int i = 1;i<=f;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			int uu = Find(u);
			int vv = Find(v);
			if (uu!=vv)
				pre[uu]=vv;
		}
		for (int i = 1;i<=n;i++)
			for (int j = i+1;j<=n;j++)
				if (Find(i)==Find(j))
					for (int k=1;k<=n;k++)
					{
						dis[i][k]=dis[j][k]=(dis[i][k] || dis[j][k]);
					}
		int l = 0;
		int r = n;
		while (l<=r)
		{
			int mid = (l+r)/2;
			if (solve(mid,kk))
				l = mid+1;
			else
				r=mid-1;
		}
		printf("%d\n",r);
	}
}




Description



Presumably, you all have known the question of stable marriage match. A girl will choose a boy; it is similar as the ever game of play-house . What a happy time as so many friends play together. And it is normal that a fight or a quarrel breaks out, but we will still play together after that, because we are kids. 

Now, there are 2n kids, n boys numbered from 1 to n, and n girls numbered from 1 to n. As you know, ladies first. So, every girl can choose a boy first, with whom she has not quarreled, to make up a family. Besides, the girl X can also choose boy Z to be her boyfriend when her friend, girl Y has not quarreled with him. Furthermore, the friendship is mutual, which means a and c are friends provided that a and b are friends and b and c are friend. 

Once every girl finds their boyfriends they will start a new round of this game―marriage match. At the end of each round, every girl will start to find a new boyfriend, who she has not chosen before. So the game goes on and on. On the other hand, in order to play more times of marriage match, every girl can accept any K boys. If a girl chooses a boy, the boy must accept her unconditionally whether they had quarreled before or not. 

Now, here is the question for you, how many rounds can these 2n kids totally play this game? 



 



Input



There are several test cases. First is an integer T, means the number of test cases. 
Each test case starts with three integer n, m, K and f in a line (3<=n<=250, 0<m<n*n, 0<=f<n). n means there are 2*n children, n girls(number from 1 to n) and n boys(number from 1 to n). 
Then m lines follow. Each line contains two numbers a and b, means girl a and boy b had never quarreled with each other. 
Then f lines follow. Each line contains two numbers c and d, means girl c and girl d are good friends. 



 



Output



For each case, output a number in one line. The maximal number of Marriage Match the children can play.



 



Sample Input



1 4 5 1 2 1 1 2 3 3 2 4 2 4 4 1 4 2 3



 



Sample Output



3



 






标签:HDU,int,查集,flow,3277,女孩,maxn,girl,include
From: https://blog.51cto.com/u_16156555/6462548

相关文章

  • HDU 3081 Marriage Match II(二分+并查集+最大流)
    题意:有N个女孩要与N个男孩玩配对游戏.每个女孩有一个可选男孩的集合(即该女孩可以选自己集合中的任意一个男孩作为该轮的搭档).然后从第一轮开始,每个女孩都要和一个不同的男孩配对.如果第一轮N个女孩都配对成功,那么就开始第二轮配对,女孩依然从自己的备选男孩集合中选择,但是不能......
  • HDU 1556 Color the ball(树状数组区间更新)
    题意:中文题思路:一道区间更新,单点查询的裸题,用线段树做更好,因为还没看到所以这里用树状数组做。树状数组标记区间的方法很特别,比如给区间[a,b]内的气球涂颜色时,我们add(a,1),add(b+1,-1),单点查询的时候sum(x)就是x这个气球被涂色的总次数。建议先在纸上自己试一下看看,有点抽象,可以这......
  • hdu2084数塔(DP)
    思路:简单的数塔DP#include<stdio.h>#include<string.h>#include<algorithm>usingnamespacestd;inta[105][105],dp[105][105];intmain(){intt,n,i,j;scanf("%d",&t);while(t--){scanf("%d",......
  • HDU 5491 The Next(构造)
    题意:给你D(D<=2^31),s1和s2,求比D大的第一个数并且这个数二进制1的数目在[s1,s2]范围里,输出这个数思路:直接从D+1算起,如果1的数目>s2那就跳过,如果s1>sum1,那么就将这个数的低位s1-sum1个0补成1,那么就是最优的了#include<bits/stdc++.h>usingnamespacestd;#defineLLlonglongint......
  • HDU 5489 Removed Interval(DP)
    题意:求去掉某一个长度为L的子串的LIS思路:画画图其实比较显然的想法是去掉这个区间的时候答案是右边以第一个数开头的LIS+左边最后一个数小于右边第一个数的LIS,为什么是右边以第一个数开头的LIS呢,因为如果是在这个L的后第二个是最佳答案的话那么我在这个“窗口”滑到L+1这个位置的时......
  • HDU 5492 Find a path(DP)
    思路:将式子化开其实就是求(n+m-1)*s1-s2的最小值,s1表示各个格子的平方和,s2表示和的平方,留意到数据范围较小,令dp[i][j][k]为走到第i行第j列当前和为k的平方和的最小值,最后答案就是(n+m-1)*dp[i][j][k]-k*k#include<bits/stdc++.h>usingnamespacestd;#defineinf1e9inta[33][3......
  • HDU 5437 Alisha’s Party(优先队列模拟)
    思路:题目比较好懂的模拟题,用一个优先队列即可     模拟的时候要注意最后还会再开一次门,把剩下的人全部放进来,开门的时间并不一定是递增的,要自己排个序,还有就是要注意开门的时候是25这种数据,就是到第二个人到了开门,然后可以放5个人进来,这样不处理的话会RE#include<bits/s......
  • HDU - 5253 连接的管道 (卡鲁斯卡尔)最小生成树
    TimeLimit: 1000MS MemoryLimit: 32768KB 64bitIOFormat: %I64d&%I64uHDU-5253连接的管道Submit StatusDescription老Jack有一片农田,以往几年都是靠天吃饭的。但是今年老天格外的不开眼,大旱。所以老Jack决定用管道将他的所有相邻的农田全部都串联起......
  • HDU - 1114 Piggy-Bank (完全背包)
    TimeLimit: 1000MS MemoryLimit: 32768KB 64bitIOFormat: %I64d&%I64uHDU-1114Piggy-BankSubmit StatusDescriptionBeforeACMcandoanything,abudgetmustbepreparedandthenecessaryfinancialsupportobtained.Themainincomeforthis......
  • HDU - 2473 (并查集+设立虚父节点(马甲))
    涉及到并查集的删除操作,比较复杂,可以利用虚设父节点的方法:例如:有n个节点,进行m次操作.首先将0~n-1的节点的父节点设置为i+n,n~2n+1的节点的父节点设置为本身,有m次操作,所以要用到m个虚节点,例如0,1,2,3,4,5的父节点为7,8,9,10,11,把他们插入2的集合,所以他们的根节点都为8,当把2从集合......