有一张 n n n个点的无向完全图,每一条边是红色或者蓝色,对于每个点 s s s求从这个点出发的一条尽量短的经过所有点的路径。
1 ≤ n ≤ 2000 1\leq n\leq 2000 1≤n≤2000
显然地猜测一下最短的长度肯定是 n n n,说是找一条路径,实际上我们是能够找到一个颜色交替只有一次的环的,然后交替位置就在 s s s的旁边。
我们构造一下,此时有两条不相交的路径 s → x , t → y s\rightarrow x,t\rightarrow y s→x,t→y,并且两条路径上颜色都相同,一条红色一条蓝色。
我们假设 s → x s\rightarrow x s→x的路径是红色,此时对于一个未加入的点 z z z,如果 ( x , z ) (x,z) (x,z)是红色或者 ( y , z ) (y,z) (y,z)是蓝色那么直接加长路径即可。
否则也就是说
(
x
,
z
)
(x,z)
(x,z)是蓝色且
(
y
,
z
)
(y,z)
(y,z)是红色,我们考虑
(
x
,
y
)
(x,y)
(x,y)之间的路径颜色,假设是红色,那么如图

我们将
y
y
y弹出路径
t
→
y
t\rightarrow y
t→y,然后加入
s
→
x
s\rightarrow x
s→x后就可以再加入
z
z
z了。
如果是蓝色同理弹另一边。
但是此时会出现两种情况:
时间复杂度: O ( n 2 ) O(n^2) O(n2)
#include
#include
#include
#include
using namespace std;
const int N=2100;
int n,G[N][N];
char s[N];
vector<int>l,r;
int main()
{
scanf("%d",&n);
if(n==2){
printf("2\n1 2\n2\n2 1\n");
return 0;
}
for(int i=2;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<i;j++)
G[i][j]=G[j][i]=(s[j]=='R');
}
for(int s=1;s<=n;s++){
int z=s%n+1,g=0;l.clear();r.clear();
l.push_back(z);r.push_back(s);g=G[s][z%n+1];
for(int x=z%n+1;x!=s;x=x%n+1){
if(G[r[r.size()-1]][x]==g)r.push_back(x);
else if(G[l[l.size()-1]][x]==!g)l.push_back(x);
else{
if(G[l[l.size()-1]][r[r.size()-1]]==g){
r.push_back(l[l.size()-1]);
r.push_back(x);l.pop_back();
if(!l.size()){
x=x%n+1;if(x==s)break;
l.push_back(z=x);
}
}
else{
l.push_back(r[r.size()-1]);
l.push_back(x);r.pop_back();
if(!r.size()){
l.pop_back();l.swap(r);
l.push_back(x);z=x;g=!g;
}
}
}
}
printf("%d\n",n);
for(int i=0;i<r.size();i++)printf("%d ",r[i]);
for(int i=l.size()-1;i>=0;i--)printf("%d ",l[i]);
putchar('\n');
}
return 0;
}