读懂题意后发现这道题最主要是要求出字典序最小的排列,考察了匈牙利算法的实质。
首先对于$D_i$的定义,我们可以解出可能的$T_i$,然后将$i$与$T_i$连边,求最大匹配。
如果最大匹配$<N$则说明$"No Answer"$。
但是要求字典序最小。
第一中方法在我$AC$后翻看题解而写的。
这个程序是根据匈牙利算法的实质写的。
对于一个待匹配点,如果从其中一条非匹配边能匹配上,则这条匹配边一定会被匹配上。
我们将所有$i$连向$T_i$的边从小到大排序,从最后一个点开始匹配,从小的$T_i$到大的$T_i$判断。最后答案一定是字典序最小的。
为什么呢?根据刚刚的总结,也就是能保证第$1$个点一定能选择最好的匹配,因为非匹配边从最好的往最坏的情况枚举,匹配上的一定就是最好的,因为假如前面没有匹配上,原因就在于选择前面的边一定不能匹配。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define re register 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i) 7 #define repd(i, a, b) for (re int i = a; i >= b; --i) 8 #define maxx(a, b) a = max(a, b); 9 #define minn(a, b) a = min(a, b); 10 #define LL long long 11 #define inf (1 << 30) 12 13 inline int read() { 14 int w = 0, f = 1; char c = getchar(); 15 while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar(); 16 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar(); 17 return w * f; 18 } 19 20 const int maxn = 1e4 + 5; 21 22 int N, D[maxn], e[maxn][5], s[maxn], t[maxn]; 23 24 int lk[maxn], pt[maxn], vis[maxn]; 25 26 bool find(int u, int tag) { 27 rep(i, s[u], t[u]) { 28 int v = e[u][i]; 29 if (vis[v] != tag) { 30 vis[v] = tag; 31 if (lk[v] == -1 || find(lk[v], tag)) { 32 lk[v] = u; 33 pt[u] = v; 34 return true; 35 } 36 } 37 } 38 return false; 39 } 40 41 int main() { 42 N = read(); 43 44 rep(i, 0, N-1) { 45 D[i] = read(); 46 e[i][1] = D[i]+i, e[i][2] = i-D[i], e[i][3] = N+i-D[i], e[i][4] = D[i]-N+i; 47 sort(e[i]+1, e[i]+5); 48 s[i] = 1, t[i] = 4; 49 while (s[i] <= 4 && e[i][s[i]] < 0) s[i]++; 50 while (t[i] > 0 && e[i][t[i]] >= N) t[i]--; 51 } 52 53 memset(vis, -1, sizeof(vis)); 54 memset(lk, -1, sizeof(lk)); 55 repd(i, N-1, 0) 56 if (!find(i, i)) { 57 printf("No Answer"); 58 return 0; 59 } 60 61 rep(i, 0, N-1) 62 printf("%d ", pt[i]); 63 64 return 0; 65 }
第二种方法是我自己想到的,比上面的代码复杂。
首先有一点:由非匹配边和匹配边交替构成的回路(断句)翻转所有边的匹配与否(断句)得到的是另一种匹配。
所以我们先找出一个最大匹配,再通过上面的结论从第一个点调整使得解更优。最后同样也能得到字典序最小的匹配。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define re register 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i) 7 #define repd(i, a, b) for (re int i = a; i >= b; --i) 8 #define maxx(a, b) a = max(a, b); 9 #define minn(a, b) a = min(a, b); 10 #define LL long long 11 #define inf (1 << 30) 12 13 inline int read() { 14 int w = 0, f = 1; char c = getchar(); 15 while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar(); 16 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar(); 17 return w * f; 18 } 19 20 const int maxn = 1e4 + 5; 21 22 int N, D[maxn], e[maxn][5], s[maxn], t[maxn]; 23 24 int lk[maxn], pt[maxn], vis[maxn]; 25 26 bool find(int u, int tag) { 27 rep(i, s[u], t[u]) { 28 int v = e[u][i]; 29 if (vis[v] != tag) { 30 vis[v] = tag; 31 if (lk[v] == -1 || find(lk[v], tag)) { 32 lk[v] = u; 33 pt[u] = v; 34 return true; 35 } 36 } 37 } 38 return false; 39 } 40 41 bool dfs(int u, int rt) { 42 rep(i, s[u], t[u]) { 43 int v = e[u][i]; 44 if (lk[v] < rt) continue; 45 if (v == pt[u]) { 46 if (u == rt) return false; 47 continue; 48 } 49 if (vis[v] != rt) { 50 vis[v] = rt; 51 if (lk[v] == rt || dfs(lk[v], rt)) { 52 lk[v] = u; 53 pt[u] = v; 54 return true; 55 } 56 } 57 } 58 return false; 59 } 60 61 int main() { 62 N = read(); 63 64 rep(i, 0, N-1) { 65 D[i] = read(); 66 e[i][1] = D[i]+i, e[i][2] = i-D[i], e[i][3] = N+i-D[i], e[i][4] = D[i]-N+i; 67 sort(e[i]+1, e[i]+5); 68 s[i] = 1, t[i] = 4; 69 while (s[i] <= 4 && e[i][s[i]] < 0) s[i]++; 70 while (t[i] > 0 && e[i][t[i]] >= N) t[i]--; 71 } 72 73 memset(vis, -1, sizeof(vis)); 74 memset(lk, -1, sizeof(lk)); 75 rep(i, 0, N-1) 76 if (!find(i, i)) { 77 printf("No Answer"); 78 return 0; 79 } 80 81 memset(vis, -1, sizeof(vis)); 82 rep(i, 0, N-1) 83 dfs(i, i); 84 85 rep(i, 0, N-1) 86 printf("%d ", pt[i]); 87 88 return 0; 89 }