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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章