博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CodeForces 132C 一道简单 dp
阅读量:4682 次
发布时间:2019-06-09

本文共 3588 字,大约阅读时间需要 11 分钟。

//CodeForces 132C

1 #include"iostream" 2 #include"cstdio" 3 #include"cstring" 4 #include"algorithm" 5 using namespace std;    //状态可达dp,其实 bool dp[110][55][220][2]; 就好 6 int dp[110][55][220][2];    //四维状态分别为:当前命令下标,逻辑空间限制(调整命令的次数)转物理空间限制,当前直线位置(设初始位置在 len 处),当前行进方向 7 char cmd[110]; 8 int n; 9 //dp[i][j][l]中存放的是有符号数表示的向量,一开始构造的状态是:当前命令下标,逻辑空间限制(调整命令的次数)转物理空间限制,当前行进方向,这样的话就会不断选取绝对值较大的值作为 dp[i][j][l] 的值,初始化的话肯定是将数组 dp 初始化为绝对值最小的 0 10 //但是对于状态 [i][j][k] ,可能存在关于原点对应的两个位置同时取到最大的绝对值,这时候我们就必须舍去其中一个值,且有可能去掉的值就是最优解的祖先状态,这样就会得到一个错误的结果。11 //于是我们必须加入一维状态用于记录位置向量的方向信息,dp[i][j][k][l],[k] 表示位置向量的方向,0 为正向,1 为 反向12 //当dp[i][j][k][l] == 0 时,dp[i][j][0][l] 和 dp[i][j][1][l] 分别为正负半轴上的两个 0 点,互不影响,且在两个 0 点处dp值又相等(均为0),恰好又满足了相互统一的性质,所以我们在做状态转移的时候不用担心作为前驱状态的 0 点是另一半轴的点从而发生 k 值变化的麻烦情况,因为我们在需要选取 0 点时,只选取处于同侧的 0 点即可13 //而且在状态转移过程中,dp[i][j][k][l],不可能会取到负值,但是在 test 16 上 wa 了...于是最后就改成了最初提到的这种写法14 15 int main()16 {17     int i,j,k,l,len,pre_pos,res = 0;18     scanf("%s%d",cmd+1,&n);19     len = strlen(cmd+1);20     dp[0][0][len][0] = 1;   //状态起点,因为在直线上行进存在两个方向,具有对称性,所以我们只选取一个方向为初始状态即可, 0 表示正向, 1 表示反向21     for(i = 1; i<=len; ++i) {22         for(j = 0; j<=n; ++j) {23             for(k = 0; k<=(len<<1); ++k) {24                 for(l = 0; l<2; ++l) {25                     if(cmd[i]=='T') {26                         pre_pos = k+(l==0?-1:1);27                         if(dp[i-1][j][k][l^1])  //(前一状态接受 ‘T’)28                             dp[i][j][k][l] = 1;29                         else if(j>=1&&pre_pos>=0&&pre_pos<=(len<<1)&&dp[i-1][j-1][pre_pos][l])  //(前一状态拒绝 ‘T’)30                             dp[i][j][k][l] = 1;31                     }32                     else {33                         pre_pos = k+(l==0?-1:1);34                         if(pre_pos>=0&&pre_pos<=(len<<1)&&dp[i-1][j][pre_pos][l])   //(前一状态接受 ‘F’)35                             dp[i][j][k][l] = 1;36                         else if(j>=1&&dp[i-1][j-1][k][l^1]) //(前一状态拒绝 ‘F’)37                             dp[i][j][k][l] = 1;38                     }39                 }40             }41         }42     }43     for(j = n; j>=0; j -= 2) {  //对同一 cmd[i] 可以多次更改,且 cmd[i]只有两种状态,意味着可以留下偶数次调整命令的机会不使用44         for(k = 0; k<=(len<<1); ++k) {45             for(l = 0; l<2; ++l) {46                 if(dp[len][j][k][l]) {47                     res = max(res,abs(k-len));48                 }49             }50         }51     }52     printf("%d\n",res);53     return 0;54 }

 

wa 在 test 16 上的写法

1 #include"iostream" 2 #include"cstdio" 3 #include"cstring" 4 #include"algorithm" 5 using namespace std; 6 int dp[110][55][2][2]; 7 char cmd[110]; 8 int n,len; 9 int main()10 {11     int i,j,k,l,res = 0;12     scanf("%s%d",cmd+1,&n);13     len = strlen(cmd+1);14     memset(dp,-1,sizeof(dp));15     dp[0][0][0][0] = 0;16     for(i = 1; i<=len; ++i) {17         for(j = 0; j<=n; ++j) {18             for(k = 0; k<2; ++k) {19                 for(l = 0; l<2; ++l) {20                     if(cmd[i]=='T') {21                         dp[i][j][k][l] = max(dp[i][j][k][l],dp[i-1][j][k][l^1]);22                         if(j>=1&&dp[i][j][k][l]
=1&&dp[i][j][k][l]
=0; j -= 2) {42 for(k = 0; k<2; ++k) {43 for(l = 0; l<2; ++l) {44 res = max(res,dp[len][j][k][l]);45 }46 }47 }48 printf("%d\n",res);49 return 0;50 }

测试数据:http://codeforces.com/contest/132/submission/2521716

反思:选取位置坐标作为状态的 dp 所写的程序不仅有较好的可读性和较低的实现难度,最关键的是需要特殊考虑的情况比只选取正负半轴标记作为状态的 dp 要少很多,充分体现了位置坐标状态的优越性。

扩展:这题网上有人用记忆化搜索过的,先挖个坑,随后补上

转载于:https://www.cnblogs.com/AC-Phoenix/p/4275750.html

你可能感兴趣的文章
js获取元素样式
查看>>
合并排序(C语言实现)
查看>>
sql 计算两时间或日期 的相差的 年、 月、 日、时、分、秒,年、月、日分别的提取...
查看>>
HDU 1176免费馅饼 DP数塔问题转化
查看>>
十进制二进制转换
查看>>
shiro实战系列(七)之Realm
查看>>
超像素、语义分割、实例分割、全景分割 傻傻分不清?
查看>>
HMM学习
查看>>
Mysql扩展之replication概述
查看>>
C++中数值的后缀
查看>>
EventModify
查看>>
C中int8_t、int16_t、int32_t、int64_t、uint8_t、size_t、ssize_t区别
查看>>
python day2 模块初识、pyc定义
查看>>
一道算法作业题(续)
查看>>
Machine Learning From Scratch-从头开始机器学习
查看>>
基础数据结构
查看>>
018-伸展树
查看>>
FPM打包工具
查看>>
20145302张薇《Java程序设计》第八周学习总结
查看>>
WebApi2官网学习记录---单元测试
查看>>