P2071 【座位安排】【二分图】

题目背景

公元二零一四年四月十七日,小明参加了省赛,在一路上,他遇到了许多问题,请你帮他解决。

题目描述

已知车上有N排座位,有\(N\times 2\)个人参加省赛,每排座位只能坐两人,且每个人都有自己想坐的排数,问最多使多少人坐到自己想坐的位置。

输入格式

第一行,一个正整数\(N\)
第二行至第\(N\times 2+1\)行,每行两个正整数\(S_{i1},S_{i2}\),为每个人想坐的排数。

输出格式

一个非负整数,为最多使得多少人满意。

输入输出样例

输入 #1

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

输出 #1

7

说明/提示

对于\(10\%\)的数据 \(N\le 10\)
对于\(30\%\)的数据 \(N\le 50\)
对于\(60\%\)的数据 \(N\le 200\)
对于\(100\%\)的数据 \(N\le 2000\)

分析

一道二分图的基础板子题。

首先每个人都有自己想坐的两排,如果每排只有一个人,那么我们直接建边求出来最大匹配就可以了,但是这个题与众不同的是每一排能够坐下两个人,那么我们在建边的时候就不能单纯的建从人到排数的边了。

每个人都有两个希望坐的排,并且每一排都可以坐下两个人,所以我们在建边的时候再向\(n+x\)\(n+y\)建一条边,其中\(x\)\(y\)都是当前这个人想要坐的排数。

建好边以后就可以直接跑匈牙利了,最后统计答案。
这里我用的是\(vector\)存图,比较好看。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e4+10;
int n;
int ans;
int match[maxn<<1];
int vis[maxn<<1];
vector<int>g[maxn<<1];
int dfs(int x){//匈牙利算法
	int siz = g[x].size();
	for(int i=0;i<siz;++i){
		int v=g[x][i];
		if(!vis[v]){
			vis[v] = 1;
			if(!match[v] || dfs(match[v])){
				match[v] = x;
				return 1;
			}
		}
	}
	return 0;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=2*n;++i){
		int x,y;
		scanf("%d%d",&x,&y);//建边
		g[i].push_back(x);
		g[i].push_back(y);
		g[i].push_back(x+n);
		g[i].push_back(y+n);
	}
	for(int i=1;i<=2*n;++i){//匈牙利
		memset(vis,0,sizeof(vis));
		ans+=dfs(i);
	}
	printf("%d\n",ans);
}
posted @ 2020-07-10 14:53  Vocanda  阅读(174)  评论(0编辑  收藏  举报