先上题目:e900:交换纸牌游戏
https://zerojudge.tw/ShowProblem?problemid=e900
题目要求和01背包的变形问题-分堆一样,要求分成两堆且数字和越接近越好。
但这个题目多了限制就是在最少的翻牌次数...。
这边提供通过的程式码:https://ideone.com/qQ5iL5
问题差异:
选某张卡片正面的点数时是加上差值且翻牌次数不变,否则必定选择反面,
加上“负的差值”且次数多一,分堆问题时只要考虑选不选某个数字,
不选时状态不变,但这题不选时因为加上“负的差值”状态会改变。
状态设定:
状态改变时会有负数,阵列不能存取负的位置所以需要做偏移,
最糟糕的情况=负最多时,每张牌的范围是(-12,12),牌数最多1000张,
总和=(-12000,12000) ... 阵列的空间要求。
base(偏移量)=所有牌的负值总和。
初始状态:用到的数字=0(做完偏移后是 base)且该状态下翻牌次数=0
cnt[ 目前使用的阵列 ][ 偏移后的数字 ]= 最少的翻牌次数
状态转移:
根据第i张牌,只需更新 pvt (上一次有纪录到的数字),避免重复纪录这一次更新
到的状态,只要检查该格位置是否第一次更新。
不翻:v(新状态)=pvt+num[0][i]-num[1][i]且 翻牌次数不变
cnt[now][v]=min(cnt[now][v],cnt[pre][pvt])
翻牌:v(新状态)=pvt+num[1][i]-num[0][i]且 翻牌次数多一
cnt[now][v]=min(cnt[now][v],cnt[pre][pvt]+1)
输出时从两堆差值=0,1(-1 or 1)... 依此类推直到找到第1个次数的状态不是
INF 就是答案。