0%

POI 2013 day 1 Maze

題目
官解

這是今年的第四名國手懲罰 (?) 之一 (QQ),所以我就來寫這個題目了。

題目大意

給一個由 LP 構成的長度 的字串 ,請構造一個簡單 邊形,滿足它的邊都和 x 或 y 軸平行、相鄰邊互相垂直,並且存在邊上的一點,滿足從那個點開始逆時針繞這個多邊形一圈,轉彎的方向順序和 所表示的相同。在 中,L 代表左轉,P 代表右轉。

題解

首先要先判斷怎樣的狀況有解。既然是繞一圈,就代表你剛好轉了一個周角,也就是 L 的數量減 P 的數量要恰好是 4。

如果把 L 當左括號、P 當右括號的話, 會是一個有四個左括號找不到配對的環狀括號字串,先把它們找出來。因為一對 LP 剛好會讓方向變回本來的方向,所以一個有效的括號字串是不會改變方向的,由此可知那四個沒人配對的 L 就會像是四邊形的四個角,剩下的部分會被它們切成四段,等同於四邊形的四個邊。

現在我們要做的事情就是:對一個有效的括號字串,構出一條邊來。舉例來說,範測 LLLLPPLL 中沒有人配的 L 就是前兩個和後兩個,中間的 LLPP 是其中一條邊,它可以長成這個樣子:

先把最高層級的括號分開來,例如 (())(()())() 就是 (())(()())(),然後對每一組分開處理,最後再直接接起來就好了。所以接下來要處理 (...) 裡面的部分,我的做法是每一對 () 都會佔據一個正方形,裡面有很多小正方形,每個小正方形就是下一層級的括號,裡面再遞迴處理。邊長的話是小正方形的邊長總和再 +2。

像是這樣,這一組括號會從正方形的左下開始、右上結束,然後小正方形的部分就是把它單獨構完後轉 90 度。至於長度的部分,A 和 D 都是邊長減 1,B 和 C 是 1,然後可以發現到每一邊都有長度是 1 的空隙,那是避免有邊黏在一起用的。

然後把同一個邊上的每一組括號構完再串起來就做好一條邊,把四條邊做完後還要想辦法把它們串起來,最簡單的方式就是把四個邊弄超長,然後把剛剛構的部分放中間,這樣就不怕中間轉來轉去的部分相撞了。

成品,輸入是 LLLPPLLLPLPPLLPL

Code

視覺化工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from matplotlib import pyplot as plt

n = int(input()) # 點的數量

lst = [int(t) for t in input().split(' ')]
fp = lst

for i in range(0, n):
x, y = [int(t) for t in input().split(' ')]

plt.plot([lst[0], x], [lst[1], y], '.-', c='blue')
lst = (x, y)
plt.plot([lst[0], fp[0]], [lst[1], fp[1]], '.-', c='blue')

plt.show()

AC Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#include <bits/stdc++.h>
#include <bits/extc++.h>

#define StarBurstStream ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define iter(a) a.begin(), a.end()
#define riter(a) a.rbegin(), a.rend()
#define lsort(a) sort(iter(a))
#define gsort(a) sort(riter(a))
#define pb(a) push_back(a)
#define eb(a) emplace_back(a)
#define pf(a) push_front(a)
#define ef(a) emplace_front(a)
#define pob pop_back()
#define pof pop_front()
#define mp(a, b) make_pair(a, b)
#define F first
#define S second
#define mt make_tuple
#define gt(t, i) get<i>(t)
#define tomax(a, b) ((a) = max((a), (b)))
#define tomin(a, b) ((a) = min((a), (b)))
#define topos(a) ((a) = (((a) % MOD + MOD) % MOD))
#define uni(a) a.resize(unique(iter(a)) - a.begin())
#define printv(a, b) {bool pvaspace=false; \
for(auto pva : a){ \
if(pvaspace) b << " "; pvaspace=true;\
b << pva;\
}\
b << "\n";}

using namespace std;
using namespace __gnu_pbds;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdd = pair<ld, ld>;
using tiii = tuple<int, int, int>;

const ll MOD = 1000000007;
const ll MAX = 1e7; // 接在每一條邊頭尾的長度,debug 的時候可以調小一點,會比較好看

template<typename A, typename B>
ostream& operator<<(ostream& o, pair<A, B> p){
return o << '(' << p.F << ',' << p.S << ')';
}

ll ifloor(ll a, ll b){
if(b < 0) a *= -1, b *= -1;
if(a < 0) return (a - b + 1) / b;
else return a / b;
}

ll iceil(ll a, ll b){
if(b < 0) a *= -1, b *= -1;
if(a > 0) return (a + b - 1) / b;
else return a / b;
}

pii operator+(pii a, pii b){
return mp(a.F + b.F, a.S + b.S);
}

pii operator-(pii a, pii b){
return mp(a.F - b.F, a.S - b.S);
}

pii operator+=(pii& a, pii b){
return a = a + b;
}

pii operator*(pii a, int b){
return mp(a.F * b, a.S * b);
}

pii operator-(pii a){
return mp(-a.F, -a.S);
}

vector<pii> ans;
pii now = mp(0, 0);

void move(pii v, int d){
d %= 4;
if(d == 0) now += v;
else if(d == 1) now += mp(-v.S, v.F);
else if(d == 2) now += -v;
else now += mp(v.S, -v.F);
ans.eb(now);
}

void move(pii to){
ans.eb(to);
now = to;
}

int type(pii seg){
if(seg.F == 0) return 1;
return 0;
}

struct block{
int w = 0, h = 0;
vector<block*> nxt;
void add(block* b){
w += b->h;
h += b->w;
nxt.eb(b);
}
};

int lp = 0;
string s;
block* solve(){
block* b = new block({2, 2});
lp++;
while(s[lp] == 'L'){
b->add(solve());
}
lp++;
return b;
}

void draw(block* b, int dir){
move(mp(b->w - 1, 0), dir);
move(mp(0, 1), dir);
for(block* nxt : b->nxt){
draw(nxt, dir + 1);
}
move(mp(0, 1), dir);
move(mp(b->w - 1, 0), dir);
}

int main(){
StarBurstStream;

string t;
cin >> t;
int n = t.size();

int cnt = 0;
for(char i : t){
if(i == 'L') cnt++;
else cnt--;
}

if(cnt != 4){
cout << "NIE\n";
return 0;
}

deque<pii> st;
for(int i = 0; i < n; i++){
if(t[i] == 'L'){
st.eb(mp(i, 1));
continue;
}
if(!st.empty() && st.back().S == 1){
st.pob;
continue;
}
st.eb(mp(i, -1));
}
while(st.front().S == -1){
st.pof;
st.pob;
}

for(int i = 0; i < 4; i++){
s.clear();
lp = 0;
for(int j = (st[i].F + 1) % n; j != st[(i + 1) % 4].F; j = (j + 1) % n){
s += t[j];
}
move(mp(MAX, 0), i);
while(lp < s.size()){
block* b = solve();
draw(b, i);
}
if(i < 3) move(mp(MAX, 0), i);
}
move(mp(ans.back().F, ans.front().S));

vector<pii> pnt;
pnt.eb(ans.back());
for(int i = 0; i + 1 < ans.size(); i++){
while(pnt.size() >= 2 && type(ans[i] - pnt.back()) == type(pnt.back() - pnt[(int)pnt.size() - 2])) pnt.pob;
pnt.eb(ans[i]);
}
while(type(pnt.back() - pnt[(int)pnt.size() - 2]) == type(pnt.back() - pnt.front())) pnt.pob;
for(pii i : pnt){
cout << i.F << " " << i.S << "\n";
}

return 0;
}