学习笔记_ Vijos1037[差值DP] 自己也不知道怎么就搞出来了

有的时候需要一点解陌生题目的能力

描述

2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难。为了纪念“9?11”事件,Mr. F决定自己用水晶来搭建一座双塔。

Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建。但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少。所以他来请你帮忙。

给定水晶的数量N(1≤N≤100)和每块水晶的高度Hi(N块水晶高度的总和不超过2000),你的任务是判断Mr. F能否用这些水晶搭建成一座双塔(两座塔有同样的高度),如果能,则输出所能搭建的双塔的最大高度,否则输出“Impossible”。

格式

输入格式

输入的第一行为一个数N,表示水晶的数量。第二行为N个数,第i个数表示第i个水晶的高度。
输出格式

输出仅包含一行,如果能搭成一座双塔,则输出双塔的最大高度,否则输出一个字符串“Impossible”。

样例1

样例输入1

5
1 3 4 5 2

样例输出1

7

来源

某校NOIP模拟题

扯淡的 题解

哇,刚刚看到这个题好懵逼啊,看了一下数据范围,好像是2重循环…然后就想到在背包中加一个维度来维护两塔的差值,然后f[i][j]代表用前i个水晶,两塔差值为j时,所得到的最大高度.
对于每一个i,都有三个决策:
1.放第i块水晶到高的一个塔上.
2.放第i块水晶到矮的塔上.
3.不放第i块水晶
于是就搞粗来方程啦~
但是我好像并不能写出了23333
嗯就是用以前的状态推出当前状态是比较困难的…于是小仙女般的我就想到用填表法啦~以当前状态出发,推出三种状态,填上三个数…

沙茶的 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<cstdio>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
#define MAXN (100+5)
#define MAXH (2000+5)
#define MAXC (2000+5)
#define INF (2000)
int f[MAXN][2*MAXC];//f[i][j]means used i diamond && the (upper-lower) is j &&the higher hight is f[i][j]
int a[MAXN];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<=n;i++)
{
for(int j=0;j<=MAXC;j++)
{
f[i][j]=-INF;
}
}
f[0][0]=0;
for(int i=0;i<=n;i++)
{
for(int j=MAXC;j>=0;j--)
{
// f[i][j]=f[i-1][j];
if(f[i][j]>=0)//从已知的状态向后推
{
f[i+1][j]=max(f[i+1][j],f[i][j]);//不放
f[i+1][a[i+1]+j]=max(f[i+1][a[i+1]+j],f[i][j]+a[i+1]);//放在较高的塔上
if(a[i+1]>=j)//放在较低的塔上
{
f[i+1][a[i+1]-j]=max(f[i+1][a[i+1]-j],(f[i][j]+a[i+1]-j));//两塔之差小于当前水晶,所以放了该水晶两塔的高低关系将对调
}
else
{
f[i+1][j-a[i+1]]=max(f[i+1][j-a[i+1]],f[i][j]);//两塔之差大于当前水晶,即使放了该水晶,高低关系也不变,高的依然高,矮的依然矮(就像我穿上增高鞋也没有gjp高QAQ)
}
}
}
}
/*for(int i=0;i<=n;i++)
{
printf("%d:\t",i);
for(int j=0; j<=7;j++)
{
printf("%d\t",f[i][j]);
}
puts("");
}*/
int ans=0;
for(int i=1;i<=n;i++)
{
ans=max(ans,f[i][0]);//要求两塔高度相等,即差值为0
}
if(ans)
printf("%d",ans);
else
printf("Impossible");
return 0;
}

by 没有dalao们可爱的 Cansult
这里写图片描述