题目链接

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;
}

SPOJ-MobileService--线性DP的更多相关文章

  1. LightOJ1044 Palindrome Partitioning(区间DP+线性DP)

    问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...

  2. Codeforces 176B (线性DP+字符串)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...

  3. hdu1712 线性dp

    //Accepted 400 KB 109 ms //dp线性 //dp[i][j]=max(dp[i-1][k]+a[i][j-k]) //在前i门课上花j天得到的最大分数,等于max(在前i-1门 ...

  4. 动态规划——线性dp

    我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...

  5. POJ 2479-Maximum sum(线性dp)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33918   Accepted: 10504 Des ...

  6. poj 1050 To the Max(线性dp)

    题目链接:http://poj.org/problem?id=1050 思路分析: 该题目为经典的最大子矩阵和问题,属于线性dp问题:最大子矩阵为最大连续子段和的推广情况,最大连续子段和为一维问题,而 ...

  7. nyoj44 子串和 线性DP

    线性DP经典题. dp[i]表示以i为结尾最大连续和,状态转移方程dp[i] = max (a[i] , dp[i - 1] + a[i]) AC代码: #include<cstdio> ...

  8. 『最大M子段和 线性DP』

    最大M子段和(51nod 1052) Description N个整数组成的序列a[1],a[2],a[3],-,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的.如果M &g ...

  9. 『最长等差数列 线性DP』

    最长等差数列(51nod 1055) Description N个不同的正整数,找出由这些数组成的最长的等差数列. 例如:1 3 5 6 8 9 10 12 13 14 等差子数列包括(仅包括两项的不 ...

  10. cf909C 线性dp+滚动数组好题!

    一开始一直以为是区间dp.. /* f下面必须有一个s 其余的s可以和任意f进行匹配 所以用线性dp来做 先预处理一下: fffssfsfs==>3 0 1 1 dp[i][j] 表示第i行缩进 ...

随机推荐

  1. [java]察看两个日期间差多少秒/小时/天

    Java 中Date类getTime()的方法返回从1970-1-1以来的毫秒数,这是下面函数运行的基础. package com.example.demo; import java.text.Par ...

  2. Mac 平台安装MySQL

    Mac 平台安装MySQL   一.下载MySQL MySQL官网上https://dev.mysql.com/downloads/mysql/,下载Community Server版 出现如下界面, ...

  3. 微信小程序 请求签名接口超时 踩坑路。。

    我们公司一般做开发都是先用测试机的接口调试功能,等功能都调试的差不多了,再换成线上的正式接口,因为正式接口要验证签名. 这几个功能都调试的差不多了,准备换成线上正式接口了,结果却出了问题,提示请求超时 ...

  4. 78 leetCode 位运算解法

    按照自己的理解题目,数组内所有的组合:假如[1,2,3,4]看成1111到0000里面的排列组合,取位运算. vector<vector > subsets(vector&nums ...

  5. Shell脚本中怎么实现用户切换实现操作

    当我们在服务器上面疯狂的进行操作的时候,我们用shell脚本来帮我们来完成一些基本的任务,但是一些命令或者一些操作需要我们不断切换用户来实现的话,在shell脚本就不那么好实现了,那么我们在shell ...

  6. 蓝牙AT模式

      一.蓝牙AT模式设置方式 在通电前按住蓝牙模块黑色按钮,接电,当蓝牙指示灯按每隔两秒闪烁一次时进入AT模式: 有3种设置方式: 1.默认设置 模块工作角色:从模式    串口参数:38400bit ...

  7. java内存回收需要了解的知识

    你是否有过这样的经历,跑得好好的Java进程,突然就瘫痪了?多数Java进程瘫痪的原因可以从java虚拟机层面找到原因. 1.什么情况下会执行gc 为了了解我们的系统为什么会不停fgc,我们需要先了解 ...

  8. MVC框架实例教程 【转载】

    1 什么是MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller ...

  9. Django边角料

    模型层表名自定义: class Record(models.Model): content=models.CharField(max_length=32,db_column='record_conte ...

  10. Linux磁盘文件系统与格式化实战(一)

    fdisk分区的实质: 用fdisk分区的实质,就是修改0磁头0磁道1扇区的前446字节之后的64字节的分区表信息. 问题:可以使用fdisk分区的磁盘大小必须小于2T,如果大于2T呢,分区就用par ...