题解:P6644 [CCO 2020] Travelling Salesperson
考虑从一个点开始,每次加入一个点 \(i\)。
记录此时红蓝交接处的点为 \(m\)。
-
若 \(m\) 不存在,只有一种颜色,直接接在 \(m\) 后面即可。
-
若 \(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;
}

浙公网安备 33010602011771号