题目传送门
题目大意
(八数码问题的树上版本)。
已经存在解的时候直接输出最少的移动步数。
否则允许加入一条边,要求输出边的端点以及最少的移动步数。
仍然无解输出-1.
不添加边的时候方案是唯一的:直接把0移动到目的地,然后判断是否有解。
考虑把$0$移动到目的后,把0当做根。因为操作可逆,这个时候是否存在解与原图是否存在解等价。
考虑此时0走到一个环上转移圈的意义:把进入点先拿出来,转上若干圈,回到起点,把原来的进入点放回环中。
所以所有不合法的位置只有两种情况:
- 构成一条子节点到父节点的链。边连在最深点和最浅点的父节点。
- 连成一条除了最高点位置正确的链。
然后可以任意再环上找一个点,计算需要转动的圈数,然后判断一下是否可行。
于是我们顺利地判断了解的存在性。考虑怎么计算最短的步数。
如果环不在0走到根的路径上,那么需要花费额外的步数走到它。
如果在,就考虑是顺着路径绕还是逆着路径绕。
表示被绕环的方向坑死,WA了一天(向上走的时候可能与环的存储顺序相反)。
Code
1 /** 2 * Codeforces 3 * Problem#627F 4 * Accepted 5 * Time: 233ms 6 * Memory: 15500k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cassert> 11 #include <cstdlib> 12 #include <cstdio> 13 #include <vector> 14 #ifndef WIN32 15 #define Auto "%lld" 16 #else 17 #define Auto "%I64d" 18 #endif 19 using namespace std; 20 typedef bool boolean; 21 22 const int N = 2e5 + 5; 23 24 #define ll long long 25 26 template <typename T> 27 void pfill(T* pst, const T* ped, T val) { 28 for ( ; pst != ped; *(pst++) = val); 29 } 30 31 FILE* fin = stdin; 32 FILE* fout = stdout; 33 34 int n; 35 int pu, pv; 36 int rta = 1, rtb = 1; 37 vector<int> cir; 38 int ar[N], br[N]; 39 int dep[N], fa[N]; 40 boolean inc[N], vis[N]; 41 vector<int> g[N]; 42 43 inline void init() { 44 fscanf(fin, "%d", &n); 45 for (int i = 1; i <= n; i++) 46 fscanf(fin, "%d", ar + i); 47 for (int i = 1; i <= n; i++) 48 fscanf(fin, "%d", br + i); 49 for (int i = 1; i <= n && ar[i]; rta = ++i); 50 for (int i = 1; i <= n && br[i]; rtb = ++i); 51 for (int i = 1, u, v; i < n; i++) { 52 fscanf(fin, "%d%d", &u, &v); 53 g[u].push_back(v); 54 g[v].push_back(u); 55 } 56 } 57 58 void dfs(int p, int fa) { 59 dep[p] = dep[fa] + 1, ::fa[p] = fa; 60 for (auto e : g[p]) 61 if (e ^ fa) 62 dfs(e, p); 63 } 64 65 int getCircle() { // 0 : no circle, -1 : no solution, 1: there exist a circle 66 int A = 0, B = 0, g; 67 for (int i = 1; i <= n; i++) 68 if (ar[i] != br[i] && (!A || dep[i] > dep[A])) 69 A = i; 70 for (int p = A; ar[p] != br[p]; p = fa[p]) 71 cir.push_back(p), inc[p] = true; 72 if (!A) 73 return 0; 74 for (int i = 1; i <= n; i++) 75 if (!inc[i] && ar[i] != br[i] && (!B || dep[i] > dep[B])) 76 B = i; 77 if (B) { 78 int s = cir.size(); 79 for (g = B; ar[g] != br[g] && !inc[g]; g = fa[g]) 80 cir.push_back(g), inc[g] = true; 81 reverse(cir.begin() + s, cir.end()); 82 } else 83 g = B = fa[cir.back()]; 84 85 if (inc[g]) 86 return -1; 87 for (int i = 1; i <= n; i++) 88 if (ar[i] != br[i] && !inc[i]) 89 return -1; 90 for (int i = A; i != g; i = fa[i]) 91 if (!inc[i]) 92 return -1; 93 for (int i = B; i != g; i = fa[i]) 94 if (!inc[i]) 95 return -1; 96 97 pu = A, pv = B; 98 if (pu > pv) 99 swap(pu, pv); 100 return 1; 101 } 102 103 inline void solve() { 104 dfs(rtb, 0); 105 for (int p = rta; fa[p]; p = fa[p]) 106 swap(ar[fa[p]], ar[p]); 107 108 int sta = getCircle(), mov = 0, walk = 0, g = 0; 109 ll res = dep[rta] - 1; 110 if (sta == -1) { 111 fputs("-1\n", fout); 112 return; 113 } 114 115 if (!sta) { 116 fprintf(fout, "0 "Auto"\n", res); 117 return; 118 } 119 120 int siz = cir.size(); 121 for (int i = 0; i < siz; i++, mov++) 122 if (ar[cir[i]] == br[cir[0]]) 123 break; 124 if (mov == siz) { 125 fputs("-1", fout); 126 return; 127 } 128 for (int i = 0; i < siz; i++) 129 if (br[cir[i]] ^ ar[cir[(i + mov) % siz]]) { 130 fputs("-1", fout); 131 return; 132 } 133 134 for (int p = rta; p; p = fa[p]) 135 vis[p] = true; 136 boolean aflag = true; 137 int sp = 0; 138 for (int i = 0; i + 1 < (signed) cir.size(); i++, sp++) 139 if (dep[cir[i + 1]] == dep[cir[i]]) 140 break; 141 for (int i = 0; i <= sp && aflag; i++) 142 if (vis[cir[i]]) 143 aflag = false; 144 for (auto p : cir) 145 walk += vis[p]; 146 if (walk) { 147 res -= walk; 148 if (aflag) 149 mov = siz - mov; 150 ll cmp1 = walk + (ll)mov * (siz + 1); 151 ll cmp2 = (ll)siz * (siz + 1) - cmp1; 152 res += min(cmp1, cmp2); 153 } else { 154 res += (ll) min(mov, siz - mov) * (siz + 1); 155 for (int i = 0; i < siz; i++) 156 if (!g || dep[cir[i]] < dep[g]) 157 g = cir[i]; 158 g = fa[g]; 159 for ( ; g && !vis[g]; res += 2, g = fa[g]); 160 } 161 162 fprintf(fout, "%d %d "Auto"\n", pu, pv, res); 163 } 164 165 int main() { 166 init(); 167 solve(); 168 return 0; 169 }
原文地址:https://www.cnblogs.com/yyf0309/p/9880294.html
时间: 2024-10-13 16:35:09