题目链接
https://www.luogu.org/problemnew/show/SP703
方法一
分析
很显然可以用一个四维的状态$f[n][a][b][c]$表示完成第i个任务时且三人位置在$a,b,c$时的答案,枚举那个人到达下个位置来状态转移
然而,三人之必须有一个人在$pos[n]$,这个位置
于是我们就枚举前两人的位置$f[n][a][b]$,枚举下谁在$pos[n]$这个位置然后状态转移就好了
但是注意有一些约束条件不能忘记,比如当$a==b$或$a==pos[n+1]$,$b==pos[n+1]$时就可能不能转移
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #define ll long long #define ri register int using std::min; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int inf=0x7fffffff-10005; int f[1005][205][205],c[205][205],pos[2005]; int n,l; int main(){ int T,ans=inf; int p,x,y; read(T); while(T--){ ans=inf; read(l),read(n); for(ri i=1;i<=l;i++){ for(ri j=1;j<=l;j++) { read(c[i][j]); for(ri k=0;k<=n;k++)f[k][i][j]=inf; } } for(ri i=1;i<=n;i++)read(pos[i]); f[0][1][2]=0; pos[0]=3; for(ri k=0;k<n;k++){ p=k+1; x=pos[k],y=pos[p]; for(ri i=1;i<=l;i++){ for(ri j=1;j<=l;j++){ if(i==j)continue; if(i!=y&&j!=y)f[p][i][j]=min(f[p][i][j],f[k][i][j]+c[x][y]); if(x!=y&&j!=y)f[p][x][j]=min(f[p][x][j],f[k][i][j]+c[i][y]); if(x!=y&&i!=y)f[p][i][x]=min(f[p][i][x],f[k][i][j]+c[j][y]); } } } for(ri i=1;i<=l;i++){ for(ri j=1;j<=l;j++)ans=min(ans,f[n][i][j]); } printf("%d\n",ans); } return 0; }
|
方法二(方法一的优化)
分析
我们发现其实枚举第$i$个任务只和$i+1$这个状态有关,用滚动数组显著减少空间消耗
个人比较喜欢异或的,非常简洁,但是不要忘记即将更新的这一维状态要设为$INF$
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #define ll long long #define ri register int using std::min; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int inf=0x3f3f3f3f; int f[2][205][205],c[205][205],pos[2005]; int n,l; int main(){ int T,ans=inf,t=0; int p,x,y; read(T); while(T--){ ans=inf; read(l),read(n); for(ri i=1;i<=l;i++){ for(ri j=1;j<=l;j++) read(c[i][j]); } for(ri i=1;i<=n;i++)read(pos[i]); memset(f,0x3f,sizeof(f)); f[0][1][2]=0; pos[0]=3; for(ri k=0;k<n;k++){ t=t^1;memset(f[t],0x3f3f3f3f,sizeof(f[t])); p=k+1; x=pos[k],y=pos[p]; for(ri i=1;i<=l;i++){ for(ri j=1;j<=l;j++){ if(i==j)continue; if(i!=y&&j!=y)f[t][i][j]=min(f[t][i][j],f[t^1][i][j]+c[x][y]); if(x!=y&&j!=y)f[t][x][j]=min(f[t][x][j],f[t^1][i][j]+c[i][y]); if(x!=y&&i!=y)f[t][i][x]=min(f[t][i][x],f[t^1][i][j]+c[j][y]); } } } for(ri i=1;i<=l;i++){ for(ri j=1;j<=l;j++) if(i!=j&&i!=pos[n]&&j!=pos[n])ans=min(ans,f[t][i][j]); } printf("%d\n",ans); } return 0; }
|