// Implementation by Claude Code - v4b_sa_improved.cpp #include #include #include #include #include #include #include #include using namespace std; static const int dx[] = {-1, 1, 0, 0}; static const int dy[] = {0, 0, -1, 1}; static const int M_PER_POS = 5; static const double TIME_LIMIT = 1.85; int N, T; int A[20][20]; using Path = vector>; using Vis = bitset<400>; inline int cell(int r, int c){ return r*20+c; } // ---- Greedy building blocks ---- int deg(int r, int c, const Vis& vis){ int cnt=0; for(int d=0;d<4;d++){int nr=r+dx[d],nc=c+dy[d];if(nr>=0&&nr=0&&nc> nbrs; for(int d=0;d<4;d++){int nr=r+dx[d],nc=c+dy[d];if(nr>=0&&nr=0&&nc()(rng)0){ int pick=uniform_int_distribution(0,total-1)(rng),acc=0; for(auto&[nr,nc]:nbrs){acc+=A[nr][nc];if(pickbest){best=fn;nextr=nr;nextc=nc;}} } vis.set(cell(nextr,nextc)); path.push_back({nextr,nextc}); added+=A[nextr][nextc]; r=nextr; c=nextc; } return added; } pair greedy_full(int sr, int sc, int vw, int dw){ Vis vis; vis.reset(); vis.set(cell(sr,sc)); Path path={{sr,sc}}; int score=A[sr][sc],r=sr,c=sc; while((int)path.size()=0&&nr=0&&ncbest){best=fn;nextr=nr;nextc=nc;}}} if(nextr<0) break; vis.set(cell(nextr,nextc)); path.push_back({nextr,nextc}); score+=A[nextr][nextc]; r=nextr; c=nextc; } return {score,path}; } pair zigzag_run(){ Path path; for(int i=0;i=0&&(int)path.size() beam_search(){ vector cur; cur.reserve(N*N); for(int i=0;i> hist(T); hist[0].resize(cur.size()); for(int i=0;i<(int)cur.size();i++) hist[0][i]={cur[i].score,cur[i].r,cur[i].c,-1}; int bscore=-1,bstep=0,bidx=0; for(int i=0;i<(int)cur.size();i++) if(cur[i].score>bscore){bscore=cur[i].score;bstep=0;bidx=i;} vector cands; cands.reserve(cur.size()*4); for(int step=1;step=N||nc<0||nc>=N||s.visited.test(cell(nr,nc)))continue;BState ns;ns.score=s.score+A[nr][nc];ns.r=(short)nr;ns.c=(short)nc;ns.parent=(short)pi;ns.visited=s.visited;ns.visited.set(cell(nr,nc));cands.push_back(ns);}} if(cands.empty()) break; sort(cands.begin(),cands.end(),[](const BState&a,const BState&b){if(a.r!=b.r)return a.rb.score;}); vector nxt; nxt.reserve(N*N*M_PER_POS); for(int i=0,sz=(int)cands.size();ibscore){bscore=nxt[i].score;bstep=step;bidx=i;} cur.swap(nxt); } Path path; for(int cs=bstep,ci=bidx;cs>=0&&ci>=0;){auto&h=hist[cs][ci];path.push_back({h.r,h.c});ci=h.parent;cs--;} reverse(path.begin(),path.end()); return {bscore,path}; } // Compute score and vis from path pair compute_score_vis(const Path& path){ Vis vis; vis.reset(); int s=0; for(auto&p:path){vis.set(cell(p.first,p.second));s+=A[p.first][p.second];} return {s,vis}; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin>>N>>T; for(int i=0;i>A[i][j]; auto t0=chrono::steady_clock::now(); auto elapsed=[&](){ return chrono::duration(chrono::steady_clock::now()-t0).count(); }; // Initial solution int best_score=-1; Path best_path; for(int i=0;i>{{1,0},{4,1}}){auto[sc,path]=greedy_full(i,j,vw,dw);if(sc>best_score){best_score=sc;best_path=path;}} } {auto[sc,path]=zigzag_run();if(sc>best_score){best_score=sc;best_path=path;}} {auto[sc,path]=beam_search();if(sc>best_score){best_score=sc;best_path=path;}} // SA mt19937 rng(42); Path cur_path=best_path; int cur_score=best_score; // Precompute prefix scores for fast cut evaluation auto get_prefix_score=[&](const Path& path, int cut)->pair{ Vis vis; vis.reset(); int s=0; for(int k=0;k()(rng); if(r01<0.45) op=0; else if(r01<0.90) op=1; else op=2; double rand_prob=(progress<0.5)?0.2:0.4; if(op==2){ // Large restart: keep only a small random prefix (5-20% of path) int cut=max(1,uniform_int_distribution(1,max(1,L/5))(rng)); auto[ps,vis]=get_prefix_score(cur_path,cut); Path new_path(cur_path.begin(),cur_path.begin()+cut); int er=cur_path[cut-1].first,ec=cur_path[cut-1].second; int added=extend_greedy(new_path,vis,er,ec,T,rng,0.8); int new_score=ps+added; double delta=new_score-cur_score; if(delta>=0||uniform_real_distribution<>()(rng)best_score){best_score=cur_score;best_path=cur_path;} } } else { // Tail-cut or head-cut // For head-cut: reverse path, do tail-cut, reverse result Path work_path=(op==1)?Path(cur_path.rbegin(),cur_path.rend()):cur_path; int wL=(int)work_path.size(); // Bias cut toward removing 10-40% from the end int min_keep=max(1,(int)(wL*0.6)); int max_keep=wL-1; int cut; if(min_keep>=max_keep) cut=min_keep; else cut=uniform_int_distribution(min_keep,max_keep)(rng); auto[ps,vis]=get_prefix_score(work_path,cut); Path new_path(work_path.begin(),work_path.begin()+cut); int er=work_path[cut-1].first,ec=work_path[cut-1].second; int added=extend_greedy(new_path,vis,er,ec,T,rng,rand_prob); int new_score=ps+added; if(op==1) reverse(new_path.begin(),new_path.end()); double delta=new_score-cur_score; if(delta>=0||uniform_real_distribution<>()(rng)best_score){best_score=cur_score;best_path=cur_path;} } } iters++; } cout<