传球游戏
题目描述:
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的: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
分析:
题目分析:
其实我觉得这跟上台阶是很相似的。也就是第 i 个 是由第 i-1 个 和 第 i+1个转移而来。
很明显就是一个动态规划了吧。
我想想
于是我们就知道状态转移方程了
dp[i][j] 表示 在i 个人 j 次传
然后 dp[i][j] = dp[i-1][j-1] + dp[i+1][j-1] 由于是个圈
不想加倍了……取个模 dp[i][j] = dp[(i-1+n)%n][j-1] + dp[(i+1)%n][j-1];
就可以了
int main(){
readdata();//这个都懂吧0.0
dp[0][0] = 1; //i个人 j次传
for(int j=1 ;j<=m ;j++)
for(int i=0 ;i<n ;i++)
{
dp[i][j] = dp[(i-1+n)%n][j-1] + dp[(i+1)%n][j-1];
}
printf("%d",dp[0][m]);
return 0;
}
纯洁的买卖
题目描述:
ALEJ并不是财迷,但是作为纯洁党的伟大领袖,不挣钱,纯洁的事业怎么能坚持下去!纯洁党现在已经有M(1<=M<=100000)元经费了。ALEJ有一个富II代朋友,叫做HSW,HSW特别喜欢高价收藏一些餐巾纸(毛泽东用过的)、袜子(恐龙穿过的)、马桶垫(还珠格格坐过的)、红领巾(毛新宇戴过的)等等,总之,没有他不买的。因此ALEJ想通过HSW这个大财主,去实现倒买倒卖拥有尽可能多的钱。
有N(1<=N<=100)件物品供他选择,
ALEJ每件物品的买入价为ci元,
HSW的收藏价为ri元。
每向HSW卖出一件物品i之后,还要向政府上交c[i]元的税。每种物品的数量都是无限的。
ALEJ想知道,通过一次买卖(种类、数量没有限制)后,纯洁党的经费能有多少。
输入格式
第一行两个整数,N,M。之后N行,每行两个整数:c[i],r[i]
输出格式
一个整数,表示一次买卖后手里最多的钱数。
样例输入
3 17
2 4
5 6
3 7
样例输出
22
分析:
很明显啊,完全背包问题。不多赘述。….
然后记住要交税……所以w[i] = r[i] - 2*c[i] (这里很关键,必须减2倍);
你只能求得利润
如果你说只减一倍不加本金…..那就大错特错了你一定想得通。。当然也许有蒙对的可能….但几率为0,因为我试了一下……..
所以必须 那样做 求得最大利润 + M (本金).
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() //其实这题不优化也行
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int m,n;
int c[110],w[110],r;
int f[100005];
void readdata(){
n = read();m = read();
for(int i = 1 ;i<=n ;i++)
{
c[i] = read();
r=read();
w[i] = r-2*c[i];
}
}
//完全背包
int main(){
readdata();
for(int i=1 ;i<=n ;i++)
for(int j=c[i];j<=m ;j++)
{
f[j] = max(f[j] , f[j-c[i]] + w[i]);
}
printf("%d",f[m]+m);
return 0;
}
多边形游戏
题目描述
多边形游戏是一种在一个具有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
分析:
我想说这真的是一道要写很多的动归
原因在于 负负得正………
于是我们得有一个来存 max 一个存min (或者多加一维)
然后就是枚举去掉边 ,每种情况下的最大值
若为t;绝对值最大
最大数+最大数
最小数+最小数
若为x
正数*正数
负数*负数
正数*负数
负数*正数
然后对于dpmax[][] 在p[] 存下可能的办法 详见代码。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define LL long long
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
#define inf 0x3f3f3f3f
int dpmin[110][110],dpmax[110][110];
// 第 i 和 j 个数运算
int v[110];
char op[110];
int main()
{ freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
int n;
int i,j,k;
mem(dpmin,inf);
mem(dpmax,-inf);
scanf("%d",&n);
getchar();
for(i=1;i<=n;i++){
scanf("%c %d",&op[i],&v[i]);
getchar();
op[i+n]=op[i];
v[i+n]=v[i];
}
for(i=1;i<=2*n;i++)
{
dpmax[i][i]=dpmin[i][i]=v[i];
if(i<2*n){
if(op[i+1]=='t')
dpmax[i][i+1]=dpmin[i][i+1]=v[i]+v[i+1];
else
dpmax[i][i+1]=dpmin[i][i+1]=v[i]*v[i+1];
}
}
for(k=3;k<=n;k++) // k区间的长度
for(i=1;i+k-1<=2*n;i++){
dpmax[i][i+k-1]=-inf;
dpmin[i][i+k-1]=inf;
for(j=i;j<i+k-1;j++){
if(op[j+1]=='t'){
dpmax[i][i+k-1]=max(dpmax[i][i+k-1],dpmax[i][j]+dpmax[j+1][i+k-1]);
dpmin[i][i+k-1]=min(dpmin[i][i+k-1],dpmin[i][j]+dpmin[j+1][i+k-1]);
}
else{
dpmax[i][i+k-1]=max(dpmax[i][i+k-1],dpmax[i][j]*dpmax[j+1][i+k-1]);
dpmax[i][i+k-1]=max(dpmax[i][i+k-1],dpmin[i][j]*dpmin[j+1][i+k-1]);
dpmax[i][i+k-1]=max(dpmax[i][i+k-1],dpmax[i][j]*dpmin[j+1][i+k-1]);
dpmax[i][i+k-1]=max(dpmax[i][i+k-1],dpmin[i][j]*dpmax[j+1][i+k-1]);
dpmin[i][i+k-1]=min(dpmin[i][i+k-1],dpmax[i][j]*dpmax[j+1][i+k-1]);
dpmin[i][i+k-1]=min(dpmin[i][i+k-1],dpmax[i][j]*dpmin[j+1][i+k-1]);
dpmin[i][i+k-1]=min(dpmin[i][i+k-1],dpmin[i][j]*dpmax[j+1][i+k-1]);
dpmin[i][i+k-1]=min(dpmin[i][i+k-1],dpmin[i][j]*dpmin[j+1][i+k-1]);
}
}
}
int p[55],cnt=0;
LL ans=-inf;
for(i=1;i<=n;i++){
if(dpmax[i][i+n-1]>ans){
ans=dpmax[i][i+n-1];
cnt=0;
p[cnt]=i;
}else if(dpmax[i][i+n-1]==ans){
p[++cnt]=i;
}
}
printf("%I64d\n",ans);
for(i=0;i<cnt;i++)
printf("%d ",p[i]);
printf("%d\n",p[i]);
return 0;
}