根据公式xjb推一下,然后就可以连边。
考虑到字典序最小,和匈牙利算法的实现过程,要倒序匹配。
#include <cmath> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #define N 40001 using namespace std; int n, cnt; int head[N], to[N], nex[N], belong[N], a[N]; bool vis[N]; vector <int> vec; inline int read() { int x = 0, f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1; for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘; return x * f; } inline bool check(int x, int y, int d) { return 0 <= x && x < n && min(abs(x - y), n - abs(x - y)) == d; } inline void add(int x, int y) { to[cnt] = y; nex[cnt] = head[x]; head[x] = cnt++; } inline bool dfs(int u) { int i, v; for(i = head[u]; ~i; i = nex[i]) { v = to[i]; if(!vis[v]) { vis[v] = 1; if(!belong[v] || dfs(belong[v])) { belong[v] = u; return 1; } } } return 0; } inline bool solve() { int i, ans = 0; for(i = n - 1; i >= 0; i--) { memset(vis, 0, sizeof(vis)); ans += dfs(i); } return ans == n; } int main() { int i, j, x, d; n = read(); memset(head, -1, sizeof(head)); for(i = 0; i < n; i++) { d = read(); vec.clear(); x = d + i; if(check(x, i, d)) vec.push_back(x); x = n - d + i; if(check(x, i, d)) vec.push_back(x); x = i - d; if(check(x, i, d)) vec.push_back(x); x = i - n + d; if(check(x, i, d)) vec.push_back(x); sort(vec.begin(), vec.end()); if(vec.size()) for(j = vec.size() - 1; j >= 0; j--) add(i, vec[j]); } if(!solve()) puts("No Answer"); else { for(i = 0; i < n; i++) a[belong[i]] = i; for(i = 0; i < n; i++) printf("%d ", a[i]); } return 0; }