hdu1421 poj2228hdu2577 这三个题目是最近做到的比较有特点的一类 由于某一些条件 比如取了一个东西 相邻的东西就会有所改变 那么一般会在朴素的转移方程上再加一维状态 0 1 代表对这一项不操作或者 操作 然后再从这个状态的意义出发推方程 会相对好做一些
hdu1421 搬寝室 经典DP模型 分析一下可以转化为 n个有序数字 取k个相邻的两个数字 代价是这两个数字的差的平方
一开始想了很久 感觉还有点像区间DP 后来仔细一想不管复杂度还是状态都是不好做 经过大神指点 dp[i][j]代表前i个数字取j个相邻的两个数字 然后加一维[0][1]分别代表取与不取 然后推出方程
dp[i][j][0] = min( dp[i-1][ j ][ 0 ] ,dp[ i - 1 ][ j ][1] )
dp[i][j][1] = dp[i-1][j-1][0] + (num[i] - num[i-1]) * (num[ i ] - num[i - 1])
然后再仔细一看发现[1]这个状态是固定的可以递推出来的 带进去可以把dp[ i ][ j ][ 1 ]消去,
代码如下(代码里面我没有把状态[ 1 ]都消去)
#include
#include
#include
#include
#include
poj2228 讲的是一头母牛睡觉的故事 总的来说 给n个数字 取m个数字 但是如果是某一连续段中第一个取的话 这个数字的值是不加到总的res里面的 比如1 2 3 4 5 6 我们选4 5 6 ,4是不加进去的 如果单独选6 ,6也是不加进去的 还有比较麻烦的是环形情况 这个地方跟上面一样 加一维【0】【1】,可以推出方程
dp[i][j][0]=max(dp[i-1][j][1] , dp[i-1][j][0]);
dp[i][j][1]=max(dp[i-1][j-1][1]+uti[i] , dp[i-1][j-1][0]);
dp[i][j][0,1]代表前i个数字取了j个数字且第j个数字不取或者取的最优解 由于环形情况代码混乱 就不贴代码了
hdu2577 比较简单的DP 打印一些大写或者小写字母 可以用capslock 也可以用shift 问怎么样使得打字次数最少
同样的dp[i][0,1]代表前i个按Lock或者shift的最优解
然后进行方程转移
if(str[i-1]>='a'&&str[i-1]<='z')
{
dp[i][0]=min(dp[i-1][0]+1,dp[i-1][1]+2);
dp[i][1]=min(dp[i-1][1]+2,dp[i][0]+2);
}
else
{
dp[i][0]=min(dp[i-1][0]+2,dp[i-1][1]+2);
dp[i][1]=min(dp[i-1][0]+2,dp[i-1][1]+1);
}
感觉做了有一些DP 但是还不够敏感 应该继续加强训练