vijos的界面真好看.jpg
50%范围是11,支持
Θ
(
n
!
)
\Theta(n!)
Θ(n!);100%的范围是16,支持
Θ
(
n
2
n
)
\Theta(n2^n)
Θ(n2n)。
很明显是状压。压缩的是“每个点是否被访问”的状态。
但是搜索的时候似乎还是得那么阶乘枚举?
毕竟是dp,是满足最优子结构的,可以宽搜来减少重复状态。
这样的话可以把暴搜的
Θ
(
n
!
)
\Theta(n!)
Θ(n!)降下
Θ
(
2
n
)
\Theta(2^n)
Θ(2n)。
或者记忆化搜索就可以dfs了
然后直接dp也可以的
注意要记录状态是从哪里传递过来的。传递是有顺序的,不能从状态里面随便找一个人传递。
#Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<ctime>
using namespace std;
int n,Ans=0x3f3f3f3f;
int dis[20][20]={};
int F[65565][20]={};
int main()
{
memset(F,0x3f,sizeof(F));
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
scanf("%d",&dis[i][j]);
}
}
for(int i=1;i<=n;++i)F[1<<i-1][i]=0;
for(int i=1;i<(1<<n)-1;++i)
{
for(int j=1;j<=n;++j)
{
if(F[i][j]==0x3f3f3f3f)continue;
if(!(i&(1<<j-1)))continue;
for(int k=1;k<=n;++k)
{
if((i&(1<<k-1)))continue;
F[i|(1<<k-1)][k]=min(F[i|(1<<k-1)][k],F[i][j]+dis[j][k]);
}
}
}
for(int i=1;i<=n;++i)Ans=min(Ans,F[(1<<n)-1][i]);
printf("%d",Ans);
return 0;
}