Skip to content

Commit 9956a27

Browse files
committed
feat: more solutions for new problems
1 parent ea10177 commit 9956a27

40 files changed

Lines changed: 6774 additions & 0 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"error": "LLM call failed after retries",
3+
"model": "gpt-5.2",
4+
"timestamp": "2026-02-04T14:51:22.332723"
5+
}
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
static uint64_t splitmix64(uint64_t x) {
5+
x += 0x9e3779b97f4a7c15ULL;
6+
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;
7+
x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;
8+
return x ^ (x >> 31);
9+
}
10+
11+
enum Act { LEFT = 0, RIGHT = 1, STEP = 2 };
12+
13+
int main() {
14+
ios::sync_with_stdio(false);
15+
cin.tie(nullptr);
16+
17+
int r, c;
18+
if (!(cin >> r >> c)) return 0;
19+
vector<string> g(r);
20+
for (int i = 0; i < r; i++) cin >> g[i];
21+
22+
vector<vector<int>> cellId(r, vector<int>(c, -1));
23+
vector<int> cellRow, cellCol;
24+
cellRow.reserve(r * c);
25+
cellCol.reserve(r * c);
26+
27+
for (int i = 0; i < r; i++) {
28+
for (int j = 0; j < c; j++) {
29+
if (g[i][j] == '.') {
30+
int id = (int)cellRow.size();
31+
cellId[i][j] = id;
32+
cellRow.push_back(i);
33+
cellCol.push_back(j);
34+
}
35+
}
36+
}
37+
38+
int M = (int)cellRow.size();
39+
if (M == 0) return 0;
40+
41+
vector<array<int,4>> stateOfCell(M);
42+
int N = M * 4;
43+
for (int cell = 0; cell < M; cell++) {
44+
for (int d = 0; d < 4; d++) stateOfCell[cell][d] = cell * 4 + d;
45+
}
46+
47+
static const int dx[4] = {-1, 0, 1, 0};
48+
static const int dy[4] = {0, 1, 0, -1};
49+
50+
vector<int> distWall(N, 0);
51+
vector<int> leftT(N), rightT(N), stepT(N);
52+
vector<int> cellOfState(N), dirOfState(N);
53+
54+
auto isWall = [&](int x, int y) -> bool {
55+
if (x < 0 || x >= r || y < 0 || y >= c) return true;
56+
return g[x][y] == '#';
57+
};
58+
59+
for (int cell = 0; cell < M; cell++) {
60+
int x0 = cellRow[cell], y0 = cellCol[cell];
61+
for (int d = 0; d < 4; d++) {
62+
int s = stateOfCell[cell][d];
63+
cellOfState[s] = cell;
64+
dirOfState[s] = d;
65+
66+
leftT[s] = stateOfCell[cell][(d + 3) & 3];
67+
rightT[s] = stateOfCell[cell][(d + 1) & 3];
68+
69+
int nx = x0 + dx[d], ny = y0 + dy[d];
70+
if (!isWall(nx, ny)) {
71+
int ncell = cellId[nx][ny];
72+
stepT[s] = stateOfCell[ncell][d];
73+
} else {
74+
stepT[s] = -1;
75+
}
76+
77+
int cnt = 0;
78+
int x = x0, y = y0;
79+
while (true) {
80+
int tx = x + dx[d], ty = y + dy[d];
81+
if (isWall(tx, ty)) break;
82+
cnt++;
83+
x = tx; y = ty;
84+
if (cnt >= 99) break;
85+
}
86+
distWall[s] = cnt;
87+
}
88+
}
89+
90+
// Compute observational equivalence classes (Moore machine minimization with step disabled when dist==0).
91+
vector<int> cls(N, 0), newcls(N, 0);
92+
vector<int> distToClass(100, -1);
93+
int initClasses = 0;
94+
for (int s = 0; s < N; s++) {
95+
int d = distWall[s];
96+
if (distToClass[d] == -1) distToClass[d] = initClasses++;
97+
cls[s] = distToClass[d];
98+
}
99+
100+
while (true) {
101+
unordered_map<uint64_t, int> mp;
102+
mp.reserve((size_t)N * 2);
103+
104+
int nextId = 0;
105+
bool same = true;
106+
for (int s = 0; s < N; s++) {
107+
int out = distWall[s];
108+
int l = cls[leftT[s]];
109+
int rcls = cls[rightT[s]];
110+
int st = (distWall[s] > 0 ? cls[stepT[s]] : -1);
111+
112+
uint64_t key = ((uint64_t)out << 48) |
113+
((uint64_t)l << 32) |
114+
((uint64_t)rcls << 16) |
115+
(uint64_t)(st + 1);
116+
117+
auto it = mp.find(key);
118+
int id;
119+
if (it == mp.end()) {
120+
id = nextId++;
121+
mp.emplace(key, id);
122+
} else {
123+
id = it->second;
124+
}
125+
newcls[s] = id;
126+
if (newcls[s] != cls[s]) same = false;
127+
}
128+
cls.swap(newcls);
129+
if (same) break;
130+
}
131+
132+
int numClasses = 0;
133+
for (int s = 0; s < N; s++) numClasses = max(numClasses, cls[s] + 1);
134+
135+
vector<int> cellMark(M, 0);
136+
int cellMarkTag = 1;
137+
138+
vector<int> classStamp(numClasses, 0), classCell(numClasses, -1);
139+
int classTag = 1;
140+
141+
vector<int> tmpCellStamp(M, 0);
142+
int tmpCellTag = 1;
143+
144+
unordered_map<uint64_t, int> seenBeliefs;
145+
seenBeliefs.reserve(1 << 16);
146+
147+
vector<int> belief(N);
148+
iota(belief.begin(), belief.end(), 0);
149+
150+
auto beliefHash = [&](const vector<int>& B, int d) -> uint64_t {
151+
uint64_t h = splitmix64((uint64_t)B.size() ^ (uint64_t)(d + 1234567));
152+
for (int s : B) h ^= splitmix64((uint64_t)s + 0x9e3779b97f4a7c15ULL);
153+
return h;
154+
};
155+
156+
auto actStr = [&](int act) -> const char* {
157+
if (act == LEFT) return "left";
158+
if (act == RIGHT) return "right";
159+
return "step";
160+
};
161+
162+
auto trans = [&](int s, int act) -> int {
163+
if (act == LEFT) return leftT[s];
164+
if (act == RIGHT) return rightT[s];
165+
return stepT[s];
166+
};
167+
168+
auto chooseAction = [&](const vector<int>& B, int curd, uint64_t bh) -> int {
169+
struct Cand {
170+
int act;
171+
int worstCells;
172+
int worstStates;
173+
int groups;
174+
int pref;
175+
};
176+
177+
array<vector<int>, 100> buckets;
178+
array<int, 100> usedFlags{};
179+
vector<int> used;
180+
used.reserve(100);
181+
182+
auto evalAct = [&](int act) -> Cand {
183+
used.clear();
184+
// We'll lazily clear buckets only when first used per dist.
185+
for (int dd : used) { (void)dd; } // no-op; used cleared.
186+
187+
int worstCells = 0, worstStates = 0, groups = 0;
188+
189+
for (int s : B) {
190+
int ns = trans(s, act);
191+
int dd = distWall[ns];
192+
if (!usedFlags[dd]) {
193+
usedFlags[dd] = 1;
194+
used.push_back(dd);
195+
buckets[dd].clear();
196+
}
197+
buckets[dd].push_back(cellOfState[ns]);
198+
}
199+
200+
for (int dd : used) {
201+
int sz = (int)buckets[dd].size();
202+
worstStates = max(worstStates, sz);
203+
groups++;
204+
205+
int tag = ++tmpCellTag;
206+
if (tmpCellTag == INT_MAX) {
207+
tmpCellTag = 1;
208+
fill(tmpCellStamp.begin(), tmpCellStamp.end(), 0);
209+
tag = ++tmpCellTag;
210+
}
211+
212+
int uniq = 0;
213+
for (int cell : buckets[dd]) {
214+
if (tmpCellStamp[cell] != tag) {
215+
tmpCellStamp[cell] = tag;
216+
uniq++;
217+
}
218+
}
219+
worstCells = max(worstCells, uniq);
220+
}
221+
222+
for (int dd : used) usedFlags[dd] = 0;
223+
224+
int pref = 0;
225+
if (act == STEP) pref = 0;
226+
else if (act == RIGHT) pref = 1;
227+
else pref = 2;
228+
229+
return Cand{act, worstCells, worstStates, groups, pref};
230+
};
231+
232+
vector<int> acts;
233+
acts.push_back(LEFT);
234+
acts.push_back(RIGHT);
235+
if (curd > 0) acts.push_back(STEP);
236+
237+
vector<Cand> cands;
238+
cands.reserve(3);
239+
for (int act : acts) cands.push_back(evalAct(act));
240+
241+
sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {
242+
if (a.worstCells != b.worstCells) return a.worstCells < b.worstCells;
243+
if (a.worstStates != b.worstStates) return a.worstStates < b.worstStates;
244+
if (a.groups != b.groups) return a.groups > b.groups;
245+
return a.pref < b.pref;
246+
});
247+
248+
int cnt = ++seenBeliefs[bh];
249+
if ((cnt >= 6) && (int)cands.size() >= 2) {
250+
// Try to escape cycles by occasionally taking the 2nd best action.
251+
if (cnt % 6 == 0) return cands[1].act;
252+
}
253+
return cands[0].act;
254+
};
255+
256+
int d;
257+
while (cin >> d) {
258+
if (d == -1) return 0;
259+
260+
// Filter belief by observed distance.
261+
vector<int> nb;
262+
nb.reserve(belief.size());
263+
for (int s : belief) if (distWall[s] == d) nb.push_back(s);
264+
belief.swap(nb);
265+
266+
if (belief.empty()) {
267+
cout << "no" << endl;
268+
return 0;
269+
}
270+
271+
// Unique cell check.
272+
int tag = ++cellMarkTag;
273+
if (cellMarkTag == INT_MAX) {
274+
cellMarkTag = 1;
275+
fill(cellMark.begin(), cellMark.end(), 0);
276+
tag = ++cellMarkTag;
277+
}
278+
int uniqueCell = -1, cellCnt = 0;
279+
for (int s : belief) {
280+
int cell = cellOfState[s];
281+
if (cellMark[cell] != tag) {
282+
cellMark[cell] = tag;
283+
uniqueCell = cell;
284+
cellCnt++;
285+
if (cellCnt > 1) break;
286+
}
287+
}
288+
if (cellCnt == 1) {
289+
cout << "yes " << (cellRow[uniqueCell] + 1) << " " << (cellCol[uniqueCell] + 1) << endl;
290+
return 0;
291+
}
292+
293+
// If two different cells are still possible but belong to the same equivalence class, impossible to resolve.
294+
int ctag = ++classTag;
295+
if (classTag == INT_MAX) {
296+
classTag = 1;
297+
fill(classStamp.begin(), classStamp.end(), 0);
298+
ctag = ++classTag;
299+
}
300+
bool impossibleNow = false;
301+
for (int s : belief) {
302+
int k = cls[s];
303+
int cell = cellOfState[s];
304+
if (classStamp[k] != ctag) {
305+
classStamp[k] = ctag;
306+
classCell[k] = cell;
307+
} else {
308+
if (classCell[k] != cell) {
309+
impossibleNow = true;
310+
break;
311+
}
312+
}
313+
}
314+
if (impossibleNow) {
315+
cout << "no" << endl;
316+
return 0;
317+
}
318+
319+
uint64_t bh = beliefHash(belief, d);
320+
int act = chooseAction(belief, d, bh);
321+
322+
cout << actStr(act) << endl;
323+
324+
// Apply action to belief (without next observation filtering yet).
325+
vector<int> after;
326+
after.reserve(belief.size());
327+
if (act == STEP) {
328+
// Must be safe: only step when d>0
329+
if (d == 0) {
330+
cout << "no" << endl;
331+
return 0;
332+
}
333+
for (int s : belief) {
334+
int ns = stepT[s];
335+
if (ns < 0) { // should not happen if filtered correctly
336+
cout << "no" << endl;
337+
return 0;
338+
}
339+
after.push_back(ns);
340+
}
341+
} else if (act == LEFT) {
342+
for (int s : belief) after.push_back(leftT[s]);
343+
} else {
344+
for (int s : belief) after.push_back(rightT[s]);
345+
}
346+
belief.swap(after);
347+
}
348+
349+
return 0;
350+
}

0 commit comments

Comments
 (0)