/*
Name: poj 1717 Dominoes
Author:UnimenSun
Date: 3/07/11 21:54
Description: 变形0-1背包
*/
/*
解题报告:
该题为变形的0-1背包,如果能做到很好的转化解决起来不是很难
这里将gap值做为背包容量(注意这里gap有可能为负值, 可以给其加上一个定值,将负值变为正值),用反转一次骨牌对gap的影响值
change[i]做为物品往背包里放,同样这个影响值,既价值同样有存在负值的情况,与是按0-1背包的思想可得到转移方程:
dp[i][j] = min(dp[i-1][j], dp[i-1][j-change[i]]+1):其中i为骨牌号,j为gap值
这里需要注意动规数组存放的值是意思,这一点必须弄清,其实该数组中存放的值为:要使差值改变gap最少的反转次数(这里要好好理解)
正是由于动规数组里存放着这样的值,因此在最后只要找到一个这样的值就行:与fix+gap最接近的i,同时dp[fix+gap-i]或dp[fix+gap+i]有值即可,注意
如果对称着都存在值,取出两者中最小的即可
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int nmax = 19870711;
const int fix = 20000;
int n;
int dp[35000];
int up, down, gap;
int change[1010];
int nright, nletf;
int main()
{
int i, j;
while(cin>>n)
{
//初始化
gap = 0;
nright = nletf = fix;
for(i=fix-n*12; i<=fix+n*12; ++i)
dp[i] = nmax;
dp[fix] = 0;
//读入数据
for(i=1; i<=n; ++i)
{
cin>>up>>down;
change[i] = (up - down) * 2;
gap += (up - down);
}
//0-1背包处理
for(i=1; i<=n; ++i)
{
if(change[i] > 0)
for(j=nright+change[i]; j>=nletf+change[i]; --j)
dp[j] = _cpp_min(dp[j], dp[j-change[i]]+1);
if(change[i] < 0)
for(j=nletf+change[i]; j<=nright+change[i]; ++j)
dp[j] = _cpp_min(dp[j], dp[j-change[i]]+1);
nright = _cpp_max(nright, nright+change[i]);
nletf = _cpp_min(nletf, nletf+change[i]);
}
//找最优解
int ans;
for(i=0; i<=n*12; ++i)
{
if(dp[fix+gap-i]<nmax || dp[fix+gap+i]<nmax)
{
ans = _cpp_min(dp[fix+gap-i], dp[fix+gap+i]);
break;
}
}
cout<<ans<<endl;
}
return 0;
}
poj 1717 Dominoes
最新推荐文章于 2021-02-23 22:55:58 发布