题目链接

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]\)时就可能不能转移

代码

#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]);
//if(p==n)ans=min(ans,min(f[n][i][j],min(f[n][i][x],f[n][x][j])));
}
}
}
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\)

代码

#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]);
//if(p==n)ans=min(ans,min(f[n][i][j],min(f[n][i][x],f[n][x][j])));
}
}
}
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;
}

最新文章

  1. highchart访问一次后台服务返回多张图表数据
  2. Liferay 6.2 改造系列之二:清理不需要的Portlet
  3. 01_Java语言基础部分(数据类型与表达式、流程控制语句、数组与方法)
  4. 页面静态化3 --- 伪静态技术之Apache的rewrite机制
  5. Javascript类型转换表
  6. oracle 的rowid和rownum
  7. JMS开发(三):JMS消息的确认方式
  8. 标准SQL语言的用法
  9. PHP单例模式编写
  10. Swift 学习Using Swift mix and match, network: 写rss读者
  11. 安卓开发笔记(十八):实现button按钮事件的三种方法
  12. Canvas:时钟
  13. 使用node.js 脚手架搭建Vue项目
  14. File Explore 中data权限修改,实体机
  15. DataX
  16. shell(2)-&amp;&amp; 与 || 逻辑或与非
  17. 交换机NTP的MD5配置
  18. CF1110G Tree-Tac-Toe(博弈论)
  19. ora-12154:tns:could not resolve the connect identifier specied
  20. php 路径问题

热门文章

  1. 性能分析 | 线上CPU100%排查
  2. SqlServer2008数据库的备份与还原
  3. swift 第五课 定义model类 和 导航栏隐藏返回标题
  4. socket编程之黏包
  5. Kuhn-Munkras算法解决二分图最优权值匹配
  6. webdriervAPI(控制浏览器及简单元素操作)
  7. EPP状态码
  8. Nginx负载均衡高可用---架构
  9. Java学习笔记-抽象类与接口
  10. TP5 生成数据库字段 和 路由 缓存来提升性能