vijos1037 搭建双塔(重庆一中高2018级信息学竞赛测验7) 解题报告
来源:互联网 发布:深圳远程网络教育 编辑:程序博客网 时间:2024/05/02 04:41
2001年9月11日,一场突发的灾难将纽约世界贸易中心大厦夷为平地,Mr. F曾亲眼目睹了这次灾难。为了纪念“9?11”事件,Mr. F决定自己用水晶来搭建一座双塔。
Mr. F有N块水晶,每块水晶有一个高度,他想用这N块水晶搭建两座有同样高度的塔,使他们成为一座双塔,Mr. F可以从这N块水晶中任取M(1≤M≤N)块来搭建。但是他不知道能否使两座塔有同样的高度,也不知道如果能搭建成一座双塔,这座双塔的最大高度是多少。所以他来请你帮忙。
给定水晶的数量N和每块水晶的高度Hi,你的任务是判断Mr. F能否用这些水晶搭建成一座双塔(两座塔有同样的高度),如果能,则输出所能搭建的双塔的最大高度,否则输出“Impossible”。
【输入格式】
第一行为一个数N,表示水晶的数量。
第二行为N个数,第i个数表示第i个水晶的高度。
【输出格式】
输出仅包含一行,如果能搭成一座双塔,则输出双塔的最大高度,否则输出一个字符串“Impossible”。
【输入样例】
5
1 3 4 5 2
【输出样例】
7
【数据范围】
50%的数据:1≤N≤20, N块水晶高度的总和不超过2000;
70%的数据:1≤N≤100, N块水晶高度的总和不超过2000;
100%的数据:1≤N≤100, N块水晶高度的总和不超过500000。
做题思路(70分解法):拿到这道题时,因为求的是双塔(两座塔高度相同)的最大高度,于是想到递推算法,根据求什么设什么,f(i,j,k)表示前i块水晶能否搭建出第一座塔高度为j,第二座塔高度为k,因为分析前i块水晶时只与前i-1块水晶有关,所以可以使用滚动数组,省去一维。分析第i块水晶,可以不搭,可以搭在第一座塔上,也可以搭在第二座塔上,所以递推方程(滚动数组)为:f(j,k)=f(j,k) || f(j-h[i],k) || f(j,k-h[i])(即只要f(j,k),f(j-h[i],k),f(j,k-h[i])中有一个可行,f(j,k)也可行)。边界条件为f(0,0)=1,即无论用多少块水晶,都可以选择不搭,此时两座塔的高度均为0。但如果这样设状态函数的话,根据题目的数据范围,N块水晶高度总和不超过500000,如果设f[500005][500005]显然会超内存(限制128M),所以为了保险起见,考试时只设了f[2005][2005]。
解题思路(正解):因为已知如果直接求什么设什么是不行的,所以要换个思路来设计状态函数,因为求的双塔高度相同,即高度差为0,所以可以运用动态规划,设f(i,j)表示前i块水晶,选择一些搭出第一座塔与第二座塔的高度差为j时,第一座塔的最大高度,这样设的话,数组只需设f[105][500005],不会超内存,但可以发现高度差j可能为负数,对此,可以运用宏定义将负数j平移为正数。同样,分析第i块水晶,可以不搭,可以搭在第一座塔上,也可以搭在第二座塔上,所以状态转移方程为f(i,j)=max(f(i-1,j),f(i-1,j-h[i]),f(i-1,j+h[i])+h[i])。边界条件为f(0,0)=0,即不选水晶,两座塔的高度差为0,求塔高也都为0。需要注意的是,因为此种设法分析前i块水晶时,仍只与前i-1块水晶有关,所以也可以使用滚动数组来优化空间,但又为了保证正确,可以用二维滚动数组,在枚举高度差j时,可以进行优化,先在输入时计算出前i块水晶的高度和sum[i](前缀和),则枚举第i块水晶时,高度差最多为sum[i],最少为-sum[i]。如果最后f(N%2,0)是小于或等于0的,说明不存在双塔,需输出“Impossible”。
#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>#define f(x,y) d[(x)][(y)+1000000] //宏定义,注意建议平移多一点,不然可能有的数据会出问题using namespace std;const int maxn=105;const int inf=1000000010;int N,sum=0;int h[maxn],s[maxn];/*f(i,j)表示前i块水晶,选择一些搭出第一座塔与第二座塔的高度差为j时,第一座塔的最大高度 f(i,j)=max(f(i-1,j),f(i-1,j-h[i]),f(i-1,j+h[i])+h[i])边界:f(0,0)=0 */int d[2][2000005]; //二维滚动数组void solve() //动态规划{for(int i=0;i<2;i++)for(int j=-sum;j<=sum;j++)f(i,j)=-inf; //初始化f(0,0)=0; //边界for(int i=1;i<=N;i++){for(int j=-s[i];j<=s[i];j++)f(i%2,j)=-inf;for(int j=-s[i];j<=s[i];j++){int t1=f((i-1)%2,j),t2=f((i-1)%2,j-h[i]),t3=f((i-1)%2,j+h[i])+h[i];f(i%2,j)=max(t1,max(t2,t3));}}if(f(N%2,0)>0) printf("%d\n",f(N%2,0));else printf("Impossible\n");/*for(int j=-s[N];j<=s[N];j++)printf("%d ",f(N%2,j));*/}int main(){freopen("tower.in","r",stdin);//freopen("tower1.out","w",stdout);scanf("%d",&N);s[0]=0;for(int i=1;i<=N;i++){scanf("%d",&h[i]);s[i]=s[i-1]+h[i]; //预处理,计算前缀和sum+=h[i]; //计算高度差的范围}solve();return 0;}
考后反思:在考试时,如果实在想不出满分程序,那么一定要保证得部份分程序的正确(不要因为题目范围太大,就盲目地把数组设太大,可能会超内存)。
- vijos1037 搭建双塔(重庆一中高2018级信息学竞赛测验7) 解题报告
- vijos1060 盒子(重庆一中高2018级信息学竞赛测验7) 解题报告
- UVA1615 高速公路(highway)(重庆一中高2018级信息学竞赛测验5) 解题报告
- RQNOJ190 拦截匪徒 (重庆一中高2018级信息学竞赛测验2) 解题报告
- UVA815 洪水(重庆一中高2018级信息学竞赛测验3) 解题报告
- POJ3069 萨鲁曼的大军(重庆一中高2018级信息学竞赛测验3) 解题报告
- 练习题GRYZ2015 足球联赛(重庆一中高2018级信息学竞赛测验4) 解题报告
- 练习题 旅行(重庆一中高2018级信息学竞赛测验4) 解题报告
- POJ3045 牛的杂技(重庆一中高2018级信息学竞赛测验4) 解题报告
- POJ3622 挑剔的美食家(重庆一中高2018级信息学竞赛测验5) 解题报告
- vijos1488 路灯改建计划(重庆一中高2018级信息学竞赛测验9) 解题报告
- Codevs4175 收费站(重庆一中高2018级信息学竞赛测验9) 解题报告
- 【动态规划练习题】 学生宿舍(重庆一中高2018级信息学竞赛测验10) 解题报告
- JSOI2010 Codevs5227 盛夏的果实(重庆一中高2018级信息学竞赛测验7) 解题报告
- 复赛模拟试题 物品选取(重庆一中高2018级信息学竞赛测验7) 解题报告
- USACO2.4.2 穿越栅栏(简单版本) (重庆一中高2018级信息学竞赛测验2) 解题报告
- UVA1625 颜色的长度(color length)(重庆一中高2018级信息学竞赛测验10) 解题报告
- USACO 月赛 劣质的草 (重庆一中高2018级信息学竞赛测验2) 解题报告
- 一种基于透明计算的智能终端软件更新方法
- Android 之高仿活动时分秒倒计时
- HDU 1232 畅通工程 (并查集)
- [开源学习_MeiZhi]首次进入App执行某操作,第二次进入则不再执行
- #508 Wiggle Sort
- vijos1037 搭建双塔(重庆一中高2018级信息学竞赛测验7) 解题报告
- Struts2中iterator标签遍历map总结
- Oracle ETL调度
- ubuntu14.04+MXnet+CPU
- iOS IPv6-only 的兼容性解决方案
- INSTALL_FAILED_INTERNAL_ERROR错误的解决办法
- F28027第八课---ADC操作解读
- Android 面试知识点归纳
- JS中offsetTop、clientTop、scrollTop、offsetTop各属性介绍