Codeforces 627F Island Puzzle - 构造

题目传送门

  传送门I

  传送门II

  传送门III

题目大意

  (八数码问题的树上版本)。

  已经存在解的时候直接输出最少的移动步数。

  否则允许加入一条边,要求输出边的端点以及最少的移动步数。

  仍然无解输出-1.

  不添加边的时候方案是唯一的:直接把0移动到目的地,然后判断是否有解。

  考虑把$0$移动到目的后,把0当做根。因为操作可逆,这个时候是否存在解与原图是否存在解等价。

  考虑此时0走到一个环上转移圈的意义:把进入点先拿出来,转上若干圈,回到起点,把原来的进入点放回环中。

  所以所有不合法的位置只有两种情况:

  1. 构成一条子节点到父节点的链。边连在最深点和最浅点的父节点。
  2. 连成一条除了最高点位置正确的链。

  然后可以任意再环上找一个点,计算需要转动的圈数,然后判断一下是否可行。

  于是我们顺利地判断了解的存在性。考虑怎么计算最短的步数。

  如果环不在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

Codeforces 627F Island Puzzle - 构造的相关文章

ZOJ 3810 - A Volcanic Island ( 构造 )

ZOJ 3810 - A Volcanic Island ( 构造 ) 题意: 给定一个N*N 的方格,需要用4种颜色进行染色, 要求:划分出N片区域,每片区域用一种颜色,且构造出的区域形状,颜色,旋转后的形状都不能相同 分析: 构造的题目一直都不是很好做,主要是因为自己智商太低.. 这个是看了郏老大的题解才会构造的,至于为什么这样构造.也说不出一个所以然来. 代码: #include <cstdio> #include <cstring> #include <algorit

Codeforces 534C Polycarpus&#39; Dice 构造

题意:给你n个筛子,第 i 个筛子有 可以表示范围 1-a[i]的数,给你最后筛子和,问你每个筛子不可能的值有多少个. 解题思路:得到每个筛子的取值范围. 解题代码: 1 // File Name: c.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月13日 星期一 00时38分58秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #includ

Codeforces 432E Square Tiling(构造+贪心)

我们通常这么写 using (SqlDataReader drm = sqlComm.ExecuteReader()) { drm.Read();//以下把数据库中读出的Image流在图片框中显示出来. MemoryStream ms = new MemoryStream((byte[])drm["Logo"]); Image img = Image.FromStream(ms); this.pictureBox1.Image = img; } 我的写数据 private void b

Codeforces 482A Diverse Permutation(构造)

题目链接:Codeforces 482A Diverse Permutation 题目大意:给定N和K,即有一个1~N的序列,现在要求找到一个排序,使得说所有的|pi?pi+1|的值有确定K种不同. 解题思路:构造,1,K+1,2,K,3,K-1,... K+2,K+3 ... N. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn

Karen and Game CodeForces - 816C (暴力+构造)

On the way to school, Karen became fixated on the puzzle game on her phone! The game is played as follows. In each level, you have a grid with n rows and mcolumns. Each cell originally contains the number 0. One move consists of choosing one row or c

CF 936C Lock Puzzle——构造

题目:http://codeforces.com/contest/936/problem/C 玩了一个小时,只能想出 5*n 的方法. 经过一番观察?考虑这样构造:已经使得 A 串的一个后缀 = B 串的一个前缀,考虑再把一个正确的字符挪到 A 串的最后面. 设该字符为 x .它之前有 len 个字符.当前已经弄好的结尾长度为 l2 . 进行这5个操作:n-len , len , n-len-l2 , l2 , n-l2+1 . 思路就是: 1&2:使得 x 变成结尾: 3:使 x 变成开头.原

CodeForces 404C Restore Graph (构造)

题意:让人构造一个图,满足每个结点边的数目不超过 k,然后给出每个结点到某个结点的最短距离. 析:很容易看出来如果可能的话,树是一定满足条件的,只要从头开始构造这棵树就好,中途超了int...找了好久. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include

codeforces #550D Regular Bridge 构造

题目大意:给定k(1≤k≤100),要求构造一张简单无向连通图,使得存在一个桥,且每一个点的度数都为k k为偶数时无解 证明: 将这个图缩边双,能够得到一棵树 那么一定存在一个叶节点,仅仅连接一条桥边 那么这个边双内部全部点度数之和为偶数 除掉连出去的桥边外度数之和为奇数 故不合法 然后k为奇数的时候我们仅仅须要构造两个对称的边双被一条桥边连接的图即可了 因为每一个点度数为k.因此每一边至少须要k+1个点 可是k+1个点奇偶性不合法.因此每一边至少须要k+2个点 如今问题转化成了给定一个度数数组

Codeforces 482B Interesting Array 构造+线段树判可行

题目链接:点击打开链接 题意: 构造一个n长的序列,m个限制: 每个限制[l, r] q 序列要满足 区间[l,r]的所有数 & 起来结果是q 思路: 直接构造,然后判可行就好了.. #include <stdio.h> #include <cstring> #include <iostream> #include <map> template <class T> inline bool rd(T &ret) { char c;