题目链接

题目大意:给定一个二分图,记\(u\)点的匹配点为\(match(u)\),求一匹配方案使得\(match(u)\quad u \in X\)序列字典序最小

二分图匹配,匈牙利


题面有点乱七八糟(还不是我菜)刚开始没有读懂,看到一堆柿子就吓得关掉了

读懂题目以后我们就可以建出来一个二分图了.

对于二分图匹配而言,我们可以用\(Dinic\)算法求解,但是如果遇到要输出方案并且还要字典序最小就很难受了(反正我是不会)。然后跑去日报现学了下匈牙利算法。

对于匈牙利算法,它的实质实际上就是一个搜索。

inline bool find(int u){
	for(int v : G[u]){
		if(!vis[v]){
			vis[v] = 1;
			if(match[v] == -1 || find(match[v])){
				match[u] = v;
				match[v] = u;
				return true;
			}
		}
	}
	return false;
}

在这之中我们可以看到,每次贪心的为\(u\)点寻找匹配点,如果\(v\)点没有被匹配,或者是原来匹配\(v\)点的\(u'\)点可以选择一个新点\(v'\)来匹配的话,我们就为\(u\)点找到了一个匹配点,并且新增了一条匹配边

那么要求字典序最小,我们可不可以用一个\(set\)代替\(vector\)存图,这样跑出来的就是字典序最小的匹配呢?

可以是可以,但是你必须得倒序进行匹配。

为什么?因为为后来点寻找匹配时可能会让前面的点重新寻找匹配点,导致丢失最优解

试想一下:你前面的点贪心找到了最优匹配点,但是你后面的点也想要这个匹配点,于是你前面的点只能重新寻找匹配点,导致丢失解

我们倒序枚举就可以保证不丢失最优解,前面的点拿走了后面点的匹配点,但是没有关系,这样从前往后的字典序还是最小的

然后注意如果有任何一个点找不到匹配点就是\(No\;Answer\)(所求的是完美匹配)

#include <cstdio>
#include <cstring>
#include <cctype>
#include <set>
using namespace std;
const int maxn = 20480;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
set<int> G[maxn];
inline void addedge(int from,int to){
	G[from].insert(to);
}
int n,match[maxn],vis[maxn],d[maxn];
inline bool find(int u){//匈牙利
	for(int v : G[u]){
		if(!vis[v]){
			vis[v] = 1;
			if(match[v] == -1 || find(match[v])){
				match[u] = v;
				match[v] = u;
				return true;
			}
		}
	}
	return false;
}
inline int to(int x){//得到变换之后的点
	if(x < 0)return x + n;
	if(x >= n)return x - n;
	return x;
}
int main(){
	n = read();
	for(int i = 0;i < n;i++)d[i] = read(),addedge(i,to(i - d[i]) + n),addedge(i,to(i + d[i]) + n);//连边
	memset(match,-1,sizeof(match));//因为存在0点,所以只能用-1来表示没有匹配点
	for(int i = n - 1;i >= 0;i--){
		memset(vis,0,sizeof(vis)); 
		if(!find(i))return printf("No Answer\n"),0;
	}
	for(int i = 0;i <= n - 1;i++)
		printf("%d%c",match[i] - n,i == n - 1 ? '\n' : ' ');
	return 0;
}

相关文章:

  • 2021-11-09
  • 2021-09-18
  • 2021-10-23
  • 2022-02-26
  • 2021-08-14
  • 2021-08-29
  • 2021-10-04
猜你喜欢
  • 2021-10-15
  • 2022-12-23
  • 2021-07-18
  • 2022-01-17
  • 2022-12-23
  • 2021-06-03
相关资源
相似解决方案