目录
1.逃生
蒜头君在玩一款逃生的游戏。在一个 n×m 的矩形地图上,蒜头位于其中一个点。地图上每个格子有加血的药剂,和掉血的火焰,药剂的药效不同,火焰的大小也不同,每个格子上有一个数字,如果格子上的数字是正数说明是一个药剂代表增加的生命值,如果是负数说明是火焰代表失去的生命值。
蒜头初始化有 v 点血量,他的血量上限是 c,任何时刻他的生命值都不能大于血量上限,如果血量为 0 则会死亡,不能继续游戏。
矩形地图上的四个角(1,1),(1,m),(n,1),(n,m)为游戏的出口。游戏中只要选定了一个出口,就必须朝着这个方向走。例如,选择了左下的出口,就只能往左和下两个方向前进,选择了右上的出口,就只能往右和上两个方向前进,左上和右下方向的出口同理。
如果成功逃生,那么剩余生命值越高,则游戏分数越高。为了能拿到最高分,请你帮忙计算如果成功逃生最多能剩余多少血量,如果不能逃生输出 −1。
输入格式
第一行依次输入整数 n,m,x,y,v,c(1<n,m≤1000,1≤x≤n,1≤y≤m,1≤v≤c≤10000), 其中 n,m 代表地图大小,(x,y) 代表蒜头君的初始位置,v 代表蒜头的初始化血量,c 代表蒜头的生命值上限。
接下来 n 行,每行有 m 个数字,代表地图信息。(每个数字的绝对值不大于100,地图中蒜头君的初始位置的值一定为 0)
输出格式
一行输出一个数字,代表成功逃生最多剩余的血量,如果失败输出 −1。
样例输入
4 4 3 2 5 10
1 2 3 4
-1 -2 -3 -4
4 0 2 1
-4 -3 -2 -1
样例输出
10
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,v,c;
int dirx[4] = {-1,-1,1,1};
int diry[4] = {-1,1,-1,1};
int a[1010][1010];
int dp[1010][1010];
int INF = 0x3f3f3f3f;
int main()
{
cin>>n>>m>>x>>y>>v>>c;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;++j){
cin>>a[i][j];
}
}
for(int t = 0;t<4;t++){
for(int i = x;i>0&&i<=n;i-=dirx[t]){
for(int j = y;j>0&&j<=m;j-=diry[t]){
if(i == x && j == y) dp[i][j] = v;
else if(i == x) dp[i][j] = min(c,dp[i][j+diry[t]] + a[i][j]);
else if(j == y) dp[i][j] = min(c,dp[i+dirx[t]][j] + a[i][j]);
else dp[i][j] = min(c,max(dp[i+dirx[t]][j],dp[i][j+diry[t]]) + a[i][j]);
if(dp[i][j] <= 0) dp[i][j] = -INF;
}
}
}
int ans = max(max(dp[1][1],dp[1][n]),max(dp[n][1],dp[n][n]));
if(ans<=0) cout<<"-1"<<endl;
else cout<<ans<<endl;
return 0;
}
2.一维消消乐
一维消消乐是一款非常简单的游戏。有 n 颗珠子排成一排,每一颗珠子有一个价值 wi(可能是负数)。游戏是这样,你可以选择如若干对相邻的珠子,让他们同时消去。每一对珠子的消失,都会使得总分数加上两颗珠子相乘的分数。注意,每个珠子只能消一次,并且珠子消去以后,还会占位。
输入格式
输入第一行一个整数n(1≤n≤10000)。
接下来一行输入 n 个整数 (−1000≤ wi ≤1000)。
输出格式
输出最大的分数。
样例输入:
8
-9 -5 -4 -2 4 -5 -4 2
样例输出:
73
#include<bits/stdc++.h>
using namespace std;
int n;
int dp[10010][2];
int a[10010];
int main()
{
cin>>n;
for(int i = 1;i<=n;i++){
cin>>a[i];
}
dp[1][0];
for(int i = 2;i<=n;i++){
dp[i][0] = max(dp[i-1][0],dp[i-1][1]);
dp[i][1] = dp[i-1][0] + a[i]*a[i-1];
}
cout<<max(dp[n][0],dp[n][1])<<endl;
return 0;
}
3.数组分组
一个长度为 n 的数组 a,我们可以把它分成任意组,每一组是一段连续的区间。比如数组1,2,3,4,5 可以分成 (1,2),(3,4,5) 两组。每个分组都有一个权值,这个权值就是分组里面每个数的乘积对1000 取模的结果。对于数组 a 的一个分组方案,总权值就是每个分组的权值和。那么对于数组 a,分组以后最大的权值和是多少?
输入格式
输入第一张一个整数 n(1≤n≤1000)。
接下来一行 n 个整数,表示数组 a,数组中每个元素都小于等于 100。
输出格式
数组最大的分组权值和。
样例输入:
7
52 26 1 36 72 48 43
样例输出:
1596
#include<bits/stdc++.h>
using namespace std;
int n;
int a[1005],pre[1005][1005],dp[1005];
int main()
{
cin>>n;
for(int i = 1;i<=n;i++){
cin>>a[i];
}
for(int i = 1;i<=n;i++){
pre[i][i] = a[i];
for(int j = i+1;j<=n;j++){
pre[i][j] = pre[i][j-1]*a[j] %1000;
}
}
dp[0] = 0;
dp[1] = a[1];
for(int i = 2;i<=n;i++){
for(int j = 0;j<i;j++){
dp[i] = max(dp[i],dp[j]+pre[j+1][i]);
}
}
cout<<dp[n]<<endl;
return 0;
}
4.墙壁涂色
蒜头君觉得白色的墙面好单调,他决定给房间的墙面涂上颜色。他买了 3 种颜料分别是红、黄、蓝,然后把房间的墙壁竖直地划分成 n 个部分,蒜头希望每个相邻的部分颜色不能相同。他想知道一共有多少种给房间上色的方案。
例如,当 n=5 时,下面就是一种合法方案。
|蓝|红|黄|红|黄|
由于墙壁是一个环形,所以下面这个方案就是不合法的。
|蓝|红|黄|红|黄|蓝|
输入格式
一个整数 n,表示房间被划分成多少部分。(1≤n≤50)
输出格式
一个整数,表示给墙壁涂色的合法方案数。
样例输入
4
样例输出
18
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
long long a[51];
a[1] = 3;
a[2] = 6;
a[3] = 6;
for(int i = 4;i<=n;i++){
a[i] = a[i-1] + a[i-2]*2;
}
cout<<a[n]<<endl;
return 0;
}
5.过河
在一个夜黑风高的晚上,有n个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不超过俩个人通过,他们只有一个手电筒,所以每次过桥后,需要有人把手电筒带回来,第i号小朋友过桥的时间为a【i】,俩个人过桥的总时间为二者中最长的。问所有小朋友过桥的总时间最短是多少。
输入格式
第一行输入一个整数n(1<n<=1000),表示n个小朋友。
第二行有n个整数ai,表示第i个小朋友过河的时间。
输出格式
输出一个整数,表示所有小朋友过河所需要的时间。
样例输入
4
1 2 5 10
样例输出
17
#include<bits/stdc++.h>
using namespace std;
int a[1005],dp[1005];
int main()
{
int n;
cin >> n;
for(int i = 0;i < n;i++) cin >> a[i];
sort(a,a + n);
dp[0] = a[0];
dp[1] = a[1];
for(int i = 2;i < n;i++) dp[i] = min(dp[i - 1] + a[0] + a[i],dp[i - 2] + a[0] + 2 * a[1] + a[i]);
cout << dp[n - 1] << endl;
return 0;
}