题解:P6644 [CCO 2020] Travelling Salesperson

题目传送门

考虑从一个点开始,每次加入一个点 \(i\)

记录此时红蓝交接处的点为 \(m\)

  1. \(m\) 不存在,只有一种颜色,直接接在 \(m\) 后面即可。

  2. \(m\) 存在,记 \(m\) 前后两个点为 \(lst,nxt\)。若 \(C_{m,i}=C_{lst,m}\),则把 \(i\) 插在 \(nxt,m\) 之间;否则,插在 \(lst,m\) 之间。然后再更新 \(m\)

这样就可以用双向链表完成构造。

细节:每次插入,都有可能让 \(m\)\(lst\) 移动,则有可能使得 \(m\) 移到链头,但是此时应该是 \(m\) 不存在,特判一下即可。

时间复杂度 \(O(n^2)\)

#include <bits/stdc++.h>
using namespace std;
const int N=2005;
int n,l[N],r[N],w[N];//w[i] 表示 i 在链上往后连的颜色
char s[N][N];
inline int get(int x,int y) {if (x<y) swap(x,y);return s[x][y]=='B';}
inline void work(int s){
    for (int i=1;i<=n;i++) l[i]=0,r[i]=-1,w[i]=-1;
    for (int i=1,m=s;i<=n;i++){
        if (i==s) continue;
        if (m==s){r[s]=i,l[i]=s,m=i,w[s]=get(s,i);continue;}
        if (r[m]==-1){//默认 m 不存在时在链尾
            r[m]=i,l[i]=m,w[m]=get(m,i);
            if (w[m]==w[l[m]]) m=i;
            continue;
        }
        int c=get(m,i),lst=l[m],nxt=r[m];
        if (c==w[m]){
            r[lst]=i,r[i]=m,l[i]=lst,l[m]=i,w[lst]=get(lst,i),w[i]=c;
            if (w[lst]==c) m=lst;else m=i;
        }
        else {
            l[nxt]=i,l[i]=m,r[i]=nxt,r[m]=i,w[i]=get(nxt,i),w[m]=c;
            if (w[i]==c) m=nxt;else m=i;
        }
        if (m==s) {while (r[m]!=-1) m=r[m];}//细节特判
    }
    printf("%d\n",n);
    while (s!=-1) printf("%d ",s),s=r[s];
    puts("");
}
int main(){
    scanf("%d",&n);
    for (int i=2;i<=n;i++) scanf("%s",s[i]+1);
    for (int i=1;i<=n;i++) work(i);
    return 0;
}
posted @ 2026-04-06 16:01  TP2010  阅读(1)  评论(0)    收藏  举报