【题解】【CF1065D Three Pieces】
Analysis
不难想到设f[p][0/1/2]表示走到标号为p的格子,目前是车/马/象的最短时间。那么转移时,需要知道从一个格子的某个状态走向另一个格子的某个状态的最短时间。
即f[p][q]=min f[p-1][y]+d[p-1,y][p,q]
那么将p,q可以压成一个状态,将同一个格子间不同状态的转化和同一个状态不同格子间的跳跃连好边,跑一遍floyed求出d数组,再转移f即可。
至于第二问在时间最短情况下,转换次数最少。实际上就是双关键字dp。这里有两个套路:
- 先预估第二关键字的最大影响范围,设为M,则将dp值改为第一关键字*M+第二关键字。这样,在第一关键字不同的情况下,最终答案一定是取决于第一关键字,第一关键字相同时,第二关键字更优的答案更优。
- 设一个与原dp数组规模完全相同的数组,表示当该状态取到最优时,第二关键字最优为多少。该数组既可以再跑完原dp数组后重新跑一遍,也可以一遍跑原dp数组一边更新该数组,具体为:当原dp数组更新时,则该数组强制更新,否则,若原dp数组的值与此次更新的值相同时,则可以更新该数组。
下面代码采用了第二种。
Code
#include<bits/stdc++.h> using namespace std; #define int long long inline int read() { int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') {w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } inline void write(int x) { if(x<0) putchar('-'),x=~(x-1); if(x>9) write(x/10); putchar('0'+x%10); } const int N=310,dirx[8]={-2,-1,1,2,2,1,-1,-2},diry[8]={1,2,2,1,-1,-2,-2,-1}; int n,a[15][15],d[N][N],minn[N][N],f[N],g[N],cnt; //0:车 1:马 2:象 signed main() { n=read();for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=read(); memset(d,0x3f,sizeof d);memset(minn,0x3f,sizeof minn);memset(f,0x3f,sizeof f);memset(g,0x3f,sizeof g); for(int i=1;i<=n*n;++i){ for(int j=0;j<3;++j) { int x=i*3+j,y=i*3+(j+1)%3; d[x][y]=d[y][x]=1; minn[x][y]=minn[y][x]=1; } } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { int p=a[i][j]*3; for(int k=1;k<=j-1;++k) { if(k<=i-1) { int x=p+2,y=a[i-k][j-k]*3+2; d[x][y]=d[y][x]=1;minn[x][y]=minn[y][x]=0; } if(k<=n-i) { int x=p+2,y=a[i+k][j-k]*3+2; d[x][y]=d[y][x]=1;minn[x][y]=minn[y][x]=0; } } for(int k=1;k<=n;++k) { if(i-k>=1) { int x=p,y=a[i-k][j]*3; d[x][y]=d[y][x]=1;minn[x][y]=minn[y][x]=0; } if(j-k>=1) { int x=p,y=a[i][j-k]*3; d[x][y]=d[y][x]=1;minn[x][y]=minn[y][x]=0; } } for(int k=0;k<8;++k) { int x=i+dirx[k],y=j+diry[k]; if(x<1||x>n||y<1||y>n) continue; d[p+1][a[x][y]*3+1]=1;minn[p+1][a[x][y]*3+1]=0; } } cnt=n*n*3+2; for(int k=3;k<=cnt;++k) { for(int i=3;i<=cnt;++i) { for(int j=3;j<=cnt;++j) { if(d[i][j]>d[i][k]+d[k][j]){ d[i][j]=d[i][k]+d[k][j];minn[i][j]=minn[i][k]+minn[k][j]; } else if(d[i][j]==d[i][k]+d[k][j]){ minn[i][j]=min(minn[i][j],minn[i][k]+minn[k][j]); } } } } for(int i=0;i<3;++i) f[3+i]=g[3+i]=0; for(int i=2;i<=n*n;++i) { // if(i==8){ // int ljh=6; // } for(int j=0;j<3;++j) { int p=i*3+j; for(int k=0;k<3;++k) { int q=(i-1)*3+k; if(f[p]>f[q]+d[q][p]){ f[p]=f[q]+d[q][p];g[p]=g[q]+minn[q][p]; } else if(f[p]==f[q]+d[q][p]) g[p]=min(g[q]+minn[q][p],g[p]); } // if(j==1){ // write(i);putchar(' ');write(f[p]);puts(""); // } } } int ans=0x3f3f3f3f3f3f3f,res=ans; for(int j=0;j<3;++j) ans=min(ans,f[cnt-j]); cout<<ans<<" "; for(int j=0;j<3;++j) if(ans==f[cnt-j]) res=min(res,g[cnt-j]); cout<<res; return 0; } /* 3 1 4 7 6 9 2 3 8 5 7+1+1 */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具