BZOJ1562 计蒜客习题-距离序列 洛谷P1963 NOI2009 变换序列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nCz1IW6I-1587115186867)(http://www.lydsy.com/JudgeOnline/images/1562_1.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GiPTbzO5-1587115186870)(http://www.lydsy.com/JudgeOnline/images/1562_2.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i3tLhCEJ-1587115186874)(http://www.lydsy.com/JudgeOnline/images/1562_3.jpg)]
Sample Input
5

1 1 2 2 1

Sample Output
1 2 4 0 3

HINT
30%的数据中N≤50;
60%的数据中N≤500;
100%的数据中N≤10000。

如果原序列中的x位置的数可以放在新序列的y位置上 就连一条x到y的边 跑一遍二分图
如果hungary()==n 则有解
由于要字典序最小 要反着跑匈牙利算法 因为匈牙利算法会让之后拓展到的结点挤掉之前结点的匹配

还要让结点从小到大排 让字典序最小
最后在dfs的过程中 同时记录link和ans

#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define v1 (i+d)%n
#define v2 (i-d+n)%n
inline int read() {
	int s = 0, f = 1; char c = getchar(); while (c<'0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
	while (c >= '0'&&c <= '9') { s = s * 10 + c - '0'; c = getchar(); }
	return s*f;
}
int n;
const int maxn = 10007;
vector<int> g[maxn << 1];
bool vis[maxn << 1];
int link[maxn << 1],ans[maxn<<1];
bool dfs(int u) {
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i];
		if (!vis[v]) {
			vis[v] = true;
			if (link[v]==-1 || dfs(link[v])) {
				link[v] = u;
				ans[u] = v;
				return true;
			}
		}
	}
	return false;
}
int hungary() {
	int res = 0;
	memset(link, -1, sizeof(link));
	for (int i = n - 1; i >= 0; i--) {
		memset(vis, false, sizeof(vis));
		if (!dfs(i)) {
			//puts("No Answer");
			return -1;
		}
		res++;
	}
	//printf("%d\n", res);
	return res;
}
int main() {
	n = read();
	int d;
	for (int i = 0; i < n; i++) {
		d = read();
		g[i].push_back(v1);
		g[i].push_back(v2);
	}
	for (int i = 0; i < n; i++) sort(g[i].begin(), g[i].end());
	//保证在dfs过程中先考虑较小的那个点
	if (hungary() == n) {
		for (int i = 0; i < n - 1; i++)
			printf("%d ", ans[i]);
		printf("%d", ans[n - 1]);
	}
	else {
		puts("No Answer");
	}
	//getchar();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章