[dp之路]7.25test
2015-07-26 20:28
274 查看
题意:
题目一:传球游戏
ball.c/cpp/pas
Time Limit:1s Memory Limit:256M
题目描述:
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到了小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并且假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
输入格式
输入文件ball.in共一行,有两个用空格隔开的整数n,m
40%的数据满足:3<=n<=30,1<=m<=20
100%的数据满足:3<=n<=30,1<=m<=30
输出格式
输出文件ball.out共一行,有一个整数,表示符合题意的方法数。
样列输入
3 3
样列输出
2
一道简单的dp
设dp[i][j]是第i步到达第j个位置的方法数,那么dp[i][j] = dp[i - 1][j + 1] + dp[i - 1][j - 1]
由于是环形,所以注意边界就好了
其实dfs也挺简单的
题目二: 纯洁的买卖
sale.c/cpp/pas
Time Limit:1s Memory Limit:256M
题目描述:
ALEJ并不是财迷,但是作为纯洁党的伟大领袖,不挣钱,纯洁的事业怎么能坚持下去!纯洁党现在已经有M(1<=M<=100000)元经费了。ALEJ有一个富II代朋友,叫做HSW,HSW特别喜欢高价收藏一些餐巾纸(毛泽东用过的)、袜子(恐龙穿过的)、马桶垫(还珠格格坐过的)、红领巾(毛新宇戴过的)等等,总之,没有他不买的。因此ALEJ想通过HSW这个大财主,去实现倒买倒卖拥有尽可能多的钱。
有N(1<=N<=100)件物品供他选择,
ALEJ每件物品的买入价为c[i](1<=c[i]<=100000)元,
HSW的收藏价为r[i](1<=r[i]<=100000)元。
每向HSW卖出一件物品i之后,还要向政府上交c[i]元的税。每种物品的数量都是无限的。
ALEJ想知道,通过一次买卖(种类、数量没有限制)后,纯洁党的经费能有多少。
输入格式
第一行两个整数,N,M。之后N行,每行两个整数:c[i],r[i]
输出格式
一个整数,表示一次买卖后手里最多的钱数。
样例输入
3 17
2 4
5 6
3 7
样例输出
22
思路:
完全裸得不能再裸的完全背包,稍微改下就行了。。。。。话说居然看错题,直接打纯的完全背包。。而且居然答案跟样例一样!!!!
设dp[i]为还剩i元经费的赚的最大值,c[i] 为第i件物品的买入,b[i]为交了税后的纯收入;
然后直接完全背包,最后输出dp[m] + m,
题目 三 : 多边形游戏
game.c/cpp/pas
Time Limit:1s Memory Limit:256M
题目描述
多边形游戏是一种在一个具有n个顶点的多边形上进行的游戏。每个顶点有个权值(整数)。如图1是一个n=4对应多边形,每个顶点上都有一个整数,每条边都有一个运算符+或者*,所有边按从1到n进行编号。
游戏都首先移除一条边,接下来可以进行如下操作:
选择一条边E和与之相关联的点V1和V2,用一个新的点替换它们,新点上的整数为V1,V2上的整数用E上的操作符运算后的结果。
没有边时游戏结束,游戏得分就是最后剩下的那个顶点上的整数。
对于图1中的多边形,如果游戏者首先去掉3,然后依次去掉1、4、2,最后得分将是0。
请你写一个程序,对于给定的多边形,计算出可能得到的最高分,并列出第一步移除哪些边可以得到这个最高分。
关于输入
输入第一行是一个正整数n(3<=n<=50),表示多边形的边数。
接下来一行是这个多边形的描述,包含n条边和n个顶点,加号边用t表示,乘号边用x表示,顶点用顶点上标的整数表示,输入按照边的编号从1到n的顺序给出。
关于输出
第一行输出可能得到的最高分。
第二行输出一些边的列表,只有第一步移除的边在这个列表中才可能得到最高分。每条边都用这个边上的编号表示,列表必须是升序的。
例子输入
4
t -7 t 4 x 2 x 5
例子输出
33
1 2
这道题好难好难好难。。。
由于随便去掉一条边,也就是将一条环断成一条链,有点像环形的石子归并。。。。那么我们就按那种思路去想,并且由于会出现负数,那么我们就不能单纯的只保留最大值,因为两个极小的负数相乘有可能会是个极大的数,所以我们应该保存最大值与最小值来判断。
若为t;绝对值最大
最大数+最大数
最小数+最小数
若为x
正数*正数
负数*负数
正数*负数
负数*正数
设dpmax[i][j][k] 为去掉第i条边,从第j条边到第k条边的合并的最大值 dpmin[i][j][k]同理
那么我们可以枚举最后一次合并的断点来转移,注意是环形,至于去掉那些边可能得到最大值,一个循环扫一遍判断是否是最大值,若是,则加入答案,不是则跳过
题目一:传球游戏
ball.c/cpp/pas
Time Limit:1s Memory Limit:256M
题目描述:
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到了小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并且假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
输入格式
输入文件ball.in共一行,有两个用空格隔开的整数n,m
40%的数据满足:3<=n<=30,1<=m<=20
100%的数据满足:3<=n<=30,1<=m<=30
输出格式
输出文件ball.out共一行,有一个整数,表示符合题意的方法数。
样列输入
3 3
样列输出
2
一道简单的dp
设dp[i][j]是第i步到达第j个位置的方法数,那么dp[i][j] = dp[i - 1][j + 1] + dp[i - 1][j - 1]
由于是环形,所以注意边界就好了
其实dfs也挺简单的
#include<iostream> #include<cstdio> using namespace std; int ans = 0; int n,m; void dfs(int j, int p) { //printf("%d %d\n",j,p); if(j == 0 && p == 1){ ans++; //printf("++\n"); return ; } if(j == 0 && p != 1)return ; if(p + 1 <= n)dfs(j - 1, p + 1); if(p + 1 > n)dfs(j - 1, 1); if(p - 1 > 0)dfs(j - 1, p - 1); if(p - 1 < 1)dfs(j - 1, n); } int main() { freopen("ball.in", "r", stdin); freopen("ball1.out", "w", stdout); scanf("%d%d", &n ,&m); dfs(m, 1); printf("%d",ans); return 0; }
题目二: 纯洁的买卖
sale.c/cpp/pas
Time Limit:1s Memory Limit:256M
题目描述:
ALEJ并不是财迷,但是作为纯洁党的伟大领袖,不挣钱,纯洁的事业怎么能坚持下去!纯洁党现在已经有M(1<=M<=100000)元经费了。ALEJ有一个富II代朋友,叫做HSW,HSW特别喜欢高价收藏一些餐巾纸(毛泽东用过的)、袜子(恐龙穿过的)、马桶垫(还珠格格坐过的)、红领巾(毛新宇戴过的)等等,总之,没有他不买的。因此ALEJ想通过HSW这个大财主,去实现倒买倒卖拥有尽可能多的钱。
有N(1<=N<=100)件物品供他选择,
ALEJ每件物品的买入价为c[i](1<=c[i]<=100000)元,
HSW的收藏价为r[i](1<=r[i]<=100000)元。
每向HSW卖出一件物品i之后,还要向政府上交c[i]元的税。每种物品的数量都是无限的。
ALEJ想知道,通过一次买卖(种类、数量没有限制)后,纯洁党的经费能有多少。
输入格式
第一行两个整数,N,M。之后N行,每行两个整数:c[i],r[i]
输出格式
一个整数,表示一次买卖后手里最多的钱数。
样例输入
3 17
2 4
5 6
3 7
样例输出
22
思路:
完全裸得不能再裸的完全背包,稍微改下就行了。。。。。话说居然看错题,直接打纯的完全背包。。而且居然答案跟样例一样!!!!
设dp[i]为还剩i元经费的赚的最大值,c[i] 为第i件物品的买入,b[i]为交了税后的纯收入;
然后直接完全背包,最后输出dp[m] + m,
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int c[200],b[200]; int n, m; long long dp[100000 + 10]; int main() { freopen("sale.in", "r", stdin); freopen("sale.out", "w", stdout); scanf("%d%d", &n ,&m); memset(dp,0,sizeof(dp)); for(int i = 1; i <= n; i++){ scanf("%d%d", &c[i], &b[i]); b[i] -= 2 * c[i]; } for(int i = 1; i <= n; i++) { for(int j = c[i]; j <= m; j++) dp[j] = max(dp[j], dp[j - c[i]] + (long long)b[i]); } printf("%I64d",dp[m] + m); return 0; }
题目 三 : 多边形游戏
game.c/cpp/pas
Time Limit:1s Memory Limit:256M
题目描述
多边形游戏是一种在一个具有n个顶点的多边形上进行的游戏。每个顶点有个权值(整数)。如图1是一个n=4对应多边形,每个顶点上都有一个整数,每条边都有一个运算符+或者*,所有边按从1到n进行编号。
游戏都首先移除一条边,接下来可以进行如下操作:
选择一条边E和与之相关联的点V1和V2,用一个新的点替换它们,新点上的整数为V1,V2上的整数用E上的操作符运算后的结果。
没有边时游戏结束,游戏得分就是最后剩下的那个顶点上的整数。
对于图1中的多边形,如果游戏者首先去掉3,然后依次去掉1、4、2,最后得分将是0。
请你写一个程序,对于给定的多边形,计算出可能得到的最高分,并列出第一步移除哪些边可以得到这个最高分。
关于输入
输入第一行是一个正整数n(3<=n<=50),表示多边形的边数。
接下来一行是这个多边形的描述,包含n条边和n个顶点,加号边用t表示,乘号边用x表示,顶点用顶点上标的整数表示,输入按照边的编号从1到n的顺序给出。
关于输出
第一行输出可能得到的最高分。
第二行输出一些边的列表,只有第一步移除的边在这个列表中才可能得到最高分。每条边都用这个边上的编号表示,列表必须是升序的。
例子输入
4
t -7 t 4 x 2 x 5
例子输出
33
1 2
这道题好难好难好难。。。
由于随便去掉一条边,也就是将一条环断成一条链,有点像环形的石子归并。。。。那么我们就按那种思路去想,并且由于会出现负数,那么我们就不能单纯的只保留最大值,因为两个极小的负数相乘有可能会是个极大的数,所以我们应该保存最大值与最小值来判断。
若为t;绝对值最大
最大数+最大数
最小数+最小数
若为x
正数*正数
负数*负数
正数*负数
负数*正数
设dpmax[i][j][k] 为去掉第i条边,从第j条边到第k条边的合并的最大值 dpmin[i][j][k]同理
那么我们可以枚举最后一次合并的断点来转移,注意是环形,至于去掉那些边可能得到最大值,一个循环扫一遍判断是否是最大值,若是,则加入答案,不是则跳过
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int n; char ope[50], tope[50]; int num[50],tnum[50]; int dpmax[50][50][50]; int dpmin[50][50][50]; int maxx; int temp1,temp2,temp3,temp4; int main() { freopen("game.in", "r", stdin); freopen("game.out", "w", stdout); memset(dpmax, -0x3f , sizeof(dpmax)); memset(dpmin, 0x3f , sizeof(dpmin)); int i, j, k, l; int path[50]; scanf("%d ", &n); for(i=0;i<2*n;i++) { if(i%2 == 0) cin>>ope[i/2]; else cin>>num[(i-1)/2]; } for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { tope[j] = ope[(i + 1 + j) %n ]; tnum[j]=num[(i + j) % n]; } for(j = 0; j < n; j++) { dpmax[i][j][j] = tnum[j]; dpmin[i][j][j] = tnum[j]; } for(j = 1; j <= n - 1; j++) { for(k = 0; k + j <= n - 1; k++) { for(l = k; l < k + j; l++)//枚举断点 { if(tope[l] == 't')//找最大值与最小值 { temp1 = dpmax[i][k][l] + dpmax[i][l + 1][k + j]; temp2 = dpmin[i][k][l] + dpmin[i][l + 1][k + j]; dpmax[i][k][k + j] = max(dpmax[i][k][k + j], max(temp1, temp2)); dpmin[i][k][k + j] = min(dpmin[i][k][k + j], min(temp1, temp2)); } else { temp1 = dpmax[i][k][l] * dpmax[i][l + 1][k + j]; temp2 = dpmin[i][k][l] * dpmin[i][l + 1][k + j]; temp3 = dpmin[i][k][l] * dpmax[i][l + 1][k + j]; temp4 = dpmax[i][k][l] * dpmin[i][l + 1][k + j]; dpmax[i][k][k + j] = max(dpmax[i][k][k + j], max(temp1, max(temp2, max(temp3, temp4)))); dpmin[i][k][k + j] = min(dpmin[i][k][k + j], min(temp1, min(temp2, min(temp3, temp4)))); } } } } } maxx = -0x3f3f3f3f; j = 0; for(i = 0;i < n; i++) { if(dpmax[i][0][n - 1] > maxx) { maxx = dpmax[i][0][n - 1]; j = 0;//因为当maxx更新后,以前的答案并不是最大值,所以我们应当重新记录 path[j++]=i + 1;//+1是因为从0开始 } else if(dpmax[i][0][n - 1]==maxx) path[j++] = i + 1; } printf("%d\n", maxx); k = j; for(j = 0;j <= k - 1; j++) printf("%d ",path[j]); return 0; }
相关文章推荐
- C语言 控制台版 推箱子
- HDU 5312 Sequence (规律题)
- No2.Add Two Numbers
- DOM对象
- DAO设计模式
- vi命令的使用
- 【MVC框架】——Global.asax文件中的RegisterGlobalFilters()和RegisterRoutes()方法
- Android Gradle Plugin指南(五)——Build Variants(构建变种版本)
- system函数
- Number Sequence 重在找规律,48一循环
- hdu 5312 Sequence【数学推导】
- (剑指Offer)面试题39:二叉树的深度
- ActiveMQ入门实例
- hdu 1712 ACboy needs your help
- UVA 120 Stacks of Flapjacks
- 慕课网-Linux达人养成计划学习笔记
- C语言 rand函数
- POJ 2406Power Strings(KMP)
- HDU 1242 Rescue 优先队列 BFS
- UVA 10859 Placing Lampposts(树DP)