傳球遊戲
題目描述:
上體育課的時候,小蠻的老師經常帶着同學們一起做遊戲。這次,老師帶着同學們一起做傳球遊戲。
遊戲規則是這樣的: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;
}