您的位置:首页 > 其它

[Poj1717]&[洛谷1282]多米诺骨牌 背包Dp

2017-08-31 21:41 267 查看
题目链接:Poj1717洛谷1282 .

—————————————-

概述

给你n对数,每一对数分为上下两部分,这两个部分各有一个值,你可以交换上下两个数的位置。记上部分的和为s1,下部分的和为s2,现求使得|s1−s2|达到最小的交换次数。

—————————————-

题解

由题目的叙述我们可以知道,每一对数要么不交换,要交换最多被交换一次,因为再交换一次就会换回来。

咦?每一组数要么不操作,要么只操作一次,和01背包怎么那么像?

那我们试着用01背包的套路来定义状态,看看可不可行。

设dp[i]表示使s1−s2=i的最小操作数,初始化dp[s1−s2]=0,其它为∞。为了方便理解,i可以取到负数。

设ai表示初始时第i组数的上半部分,bi表示下半部分,那么此时这一组数i的差为d=ai−bi。

不妨先令ai>bi,假如我们选择不交换,那么差还是d,假如交换就变成了−d,s1−s2减少了2×d。

所以我们可以得到状态转移方程:dp[i]=dp[i+2×d]+1.

对于ai<bi,交换之后会使s1−s2增加2×d,那么转移方程则是:dp[i]=dp[i−2×d]+1.

最后统计答案的时候就从dp[0]开始左右扩展,假如有dp[i]不为∞,那么答案就是dp[i].

差不多就是这样了?好像的确没有后效性。

至于i的下标会取到负数,我们可以将数组整体向数轴正半轴平移,这样就能使所有的i取到正数了。

—————————————-

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define For(i,j,k) for(register int i=j; i<=(int)k; ++i)
#define Forr(i,j,k) for(register int i=j; i>=(int)k; --i)
#define INF 0x3f3f3f3f
using namespace std;

const int maxn = 1000+5;
const int num = 5050;

int n, s, Ans;
int a[maxn], dp[(maxn*6)<<1];

inline void read(int &x){
char c;
while((c=getchar())<'0' || c>'9');
x = c^48;
while((c=getchar())>='0' && c<='9')
x = x*10+(c^48);
}

inline void chkmin(int &x, int y){
if(y < x)
x = y;
}

int main(){
int x, y, d;

read(n);
For(i, 1, n){
read(x), read(y);
s += (a[i] = x-y);
}

memset(dp, INF, sizeof(dp));
dp[s+num] = 0;//初始化,加num即让数组整体向右平移.
For(i, 1, n)
if(!a[i])    continue;
else if(a[i] > 0){//ai > bi 的情况.
d = a[i]<<1;
For(j, -5000+num, 5000-d+num)//5000为s1-s2的最大值.
chkmin(dp[j], dp[j+d]+1);
}
else{//ai < bi 的情况.
d = (-a[i])<<1;
Forr(j, 5000+num, -5000+d+num)
chkmin(dp[j], dp[j-d]+1);
}

Ans = INF;
if(dp[num] != INF)    Ans = dp[num];
else{
For(i, 1, 5000){
if(dp[num-i] != INF)    chkmin(Ans, dp[num-i]);
if(dp[num+i] != INF)    chkmin(Ans, dp[num+i]);
if(Ans != INF)    break;
}//从dp[0]开始左右扩展,统计答案.
}

printf("%d", Ans);
return 0;
}


—————————————-

小结

此题考察的算法其实比较基础,重点在于分析问题原本的性质,即每一组数只有(不交换\交换一次)这两种选择。当分析出这题的本质就是01背包时,解法自然而然就出来了。

—————————————-

——wrote by miraclejzd.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: