龙与地下城游戏
题目
给定一个二维数组map,含义是一张地图。游戏规则如下:
1、骑士从左上角出发,每次只能向右或向下走,最后到达右下角见到公主。
2、地图中每个位置的值表示骑士的遭遇。如果是负数,此处有怪兽,要让骑士损失血量。如果是非负数,代表此处有血瓶,可以让骑士回血。
3、骑士从左上角到右下角的过程中,走到任何一个位置时,血量都不能少于1.
为了保证能见到公主,初始血量至少是多少?根据map,返回初始血量。
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int minHP1(vector<vector<int>> mp)
{
if (mp.size() < 1 || mp[0].size() < 1)
return 1;
int row = mp.size();
int col = mp[0].size();
vector<vector<int>> dp(row, vector<int>(col, 0));
dp[row - 1][col - 1] = mp[row - 1][col - 1] > 0 ? 1 : -mp[row - 1][col - 1] + 1;
for (int j = col - 2; j >= 0; j--)
{
dp[row - 1][j] = max(dp[row - 1][j + 1] - mp[row - 1][j], 1);
}
int right = 0;
int down = 0;
for (int i = row - 2; i >= 0; i--)
{
dp[i][col-1] = max(dp[i + 1][col - 1] - mp[i][col - 1], 1);
for (int j = col - 2; j >= 0; j--)
{
right = max(dp[i][j + 1] - mp[i][j], 1);
down = max(dp[i + 1][j] - mp[i][j], 1);
dp[i][j] = min(right, down);
}
}
return dp[0][0];
}
//空间压缩
int minHp2(vector<vector<int>> mp)
{
if (mp.size() < 1 || mp[0].size() < 1)
return 1;
int more = max(mp.size(), mp[0].size());
int less = min(mp.size(), mp[0].size());
bool rowMore = more == mp.size();
vector<int> dp(less, 0);
int tmp = mp[mp.size() - 1][mp[0].size() - 1];
dp[less - 1] = tmp > 0 ? 1 : -tmp + 1;
int row = 0;
int col = 0;
for (int j = less - 2; j >= 0; j--)
{
row = rowMore ? more - 1 : j;
col = rowMore ? j : more - 1;
dp[j] = max(dp[j + 1] - mp[row][col], 1);
}
int choosen1 = 0;
int choosen2 = 0;
for (int i = more - 2; i >= 0; i--)
{
row = rowMore ? i : less - 1;
col = rowMore ? less - 1 : i;
dp[less - 1] = max(dp[less - 1] - mp[row][col], 1);
for (int j = less - 2; j >= 0; j--)
{
row = rowMore ? i : j;
col = rowMore ? j : i;
choosen1 = max(dp[j] - mp[row][col], 1);
choosen2 = max(dp[j + 1] - mp[row][col], 1);
dp[j] = min(choosen1, choosen2);
}
}
return dp[0];
}
int main()
{
int m, n;
cin >> m >> n;
vector<vector<int>> in(m, vector<int>(n, 0));
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
cin >> in[i][j];
}
}
int res1 = minHP1(in);
int res2 = minHp2(in);
cout << res1 << " " << res2 << endl;
getchar();
return 0;
}
数字字符串转换为字母组合的种数
题目
给定一个字符串str,str全部由数字字符组成,如果str中某一个或某相邻两个字符组成的子串值在1~26之间,则这个子串可以转换成一个字母。规定‘1’转换为‘A’,‘2’转换为‘B’,…,‘26’转换成‘Z’。实现一个函数,求str有多少种不同的转换结果,并返回种数。
代码
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
//递归
int process(string str, int i)
{
if (i == str.size())
return 1;
if (str[i] == '0')
return 0;
int res = process(str, i + 1);
if (i + 1 < str.size() && (str[i] - '0') * 10 + str[i + 1] - '0' < 27)
res += process(str, i + 2);
return res;
}
int num1(string str)
{
if (str.size() < 1 || str == "")
return 0;
return process(str, 0);
}
int num2(string str)
{
if (str.size() < 1|| str == "")
return 0;
int cur = str[str.size() - 1] == '0' ? 0 : 1;
int next = 1;
int tmp = 0;
for (int i = str.size() - 2; i >= 0; i--)
{
if (str[i] == '0')
{
next = cur;
cur = 0;
}
else
{
tmp = cur;
if ((str[i] - '0') * 10 + str[i + 1] - '0' < 27)
cur += next;
next = tmp;
}
}
return cur;
}
int main()
{
string s;
getline(cin, s);
int res1 = num1(s);
int res2 = num2(s);
cout << res1 << " " << res2 << endl;
getchar();
return 0;
}
表达式得到期望结果的组成种数
题目
给定一个只由0(假)、1(真)、&(逻辑与)、|(逻辑或)和^(异或)五种字符组成的字符串express。再给定一个布尔值desired。返回express能有多少种组合方式,可以达到desired的成果。
代码
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
/*首先判断表达式是否有效,以下几个标准:1、表达式长度必须为奇数
2、表达式下标为偶数的位置的字符一定是‘0’或‘1’
3、表达式下标为奇数位置的字符一定是‘&’或‘|’或'^'*/
bool isValid(string str)
{
if ((str.size() & 1) == 0)
return false;
int len = str.size();
for (int i = 0; i < len; i = i + 2)
{
if ((str[i] != '1') && (str[i] != '0'))
return false;
}
for (int i = 1; i < len; i += 2)
{
if ((str[i] != '&') && (str[i] != '|') && (str[i] != '^'))
return false;
}
return true;
}
/*如果为真之后,递归判断有多少种划分方式,累加给定结果的不同划分方式
得到最后结果*/
int p(string str, bool desired, int l, int r)
{
if (l == r)
{
if (str[l] == '1')
return desired ? 1 : 0;
else
return desired ? 0 : 1;
}
int res = 0;
if (desired)
{
for (int i = l + 1; i < r; i += 2)
{
switch (str[i])
{
case '&':
res += p(str, true, l, i - 1) * p(str, true, i + 1, r);
break;
case '|':
res += p(str, true, l, i - 1) * p(str, false, i + 1, r);
res += p(str, false, l, i - 1) * p(str, true, i + 1, r);
res += p(str, true, l, i - 1) * p(str, true, i + 1, r);
break;
case '^':
res += p(str, true, l, i - 1) * p(str, false, i + 1, r);
res += p(str, false, l, i - 1) * p(str, true, i + 1, r);
break;
}
}
}
else
{
for (int i = l + 1; i < r; i += 2)
{
switch (str[i])
{
case '&':
res += p(str, false, l, i - 1) * p(str, true, i + 1, r);
res += p(str, true, l, i - 1) * p(str, false, i + 1, r);
res += p(str, false, l, i - 1) * p(str, false, i + 1, r);
break;
case '|':
res += p(str, false, l, i - 1) * p(str, false, i + 1, r);
break;
case '^':
res += p(str, true, l, i - 1) * p(str, true, i + 1, r);
res += p(str, false, l, i - 1) * p(str, false, i + 1, r);
break;
}
}
}
return res;
}
int num1(string str, bool desired)
{
if (str.size() < 1 || str == "")
return 0;
if (!isValid(str))
return 0;
return p(str, desired, 0, str.size() - 1);
}
int num2(string str, bool desired)
{
if (str.size() < 1 || str == "")
return 0;
if (!isValid(str))
return 0;
int len = str.size();
vector<vector<int>> t(len, vector<int>(len, 0));
vector<vector<int>> f(len, vector<int>(len, 0));
t[0][0] = str[0] == '0' ? 0 : 1;
f[0][0] = str[0] == '1' ? 0 : 1;
for (int i = 2; i < len; i += 2)
{
t[i][i] = str[i] == '0' ? 0 : 1;
f[i][i] = str[i] == '1' ? 0 : 1;
for (int j = i - 2; j >= 0; j -= 2)
{
for (int k = j; k < i; k += 2)
{
if (str[k + 1] == '&')
{
t[j][i] += t[j][k] * t[k + 2][i];
f[j][i] += (f[j][k] + t[j][k]) * f[k + 2][i] + f[j][k] * t[k + 2][i];
}
else if (str[k + 1] == '|')
{
t[j][i] += (f[j][k] + t[j][k]) * t[k + 2][i] + t[j][k] * f[k + 2][i];
t[j][i] += f[j][k] * f[k + 2][i];
}
else
{
t[j][i] += f[j][k] * t[k + 2][i] + t[j][k] * f[k + 2][i];
f[j][i] += f[j][k] * f[k + 2][i] + t[j][k] * t[k + 2][i];
}
}
}
}
return desired ? t[0][len - 1] : f[0][len - 1];
}
int main()
{
string s;
getline(cin, s);
bool des = false;
int res1 = num1(s, des);
int res2 = num2(s, des);
cout << res1 << " " << res2 << endl;
getchar();
return 0;
}
排成一条线的纸牌博弈问题
题目
给定一个整形数组arr,代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明。请返回最后获胜者的分数。
代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int s(int arr[], int i, int j);
int f(int arr[], int i, int j);
int s(int arr[], int i, int j)
{
if (i == j)
return 0;
return min(f(arr, i + 1, j), f(arr, i, j - 1));
}
int f(int arr[], int i, int j)
{
if (i == j)
return arr[i];
return max(arr[i] + s(arr, i + 1, j), arr[j] + s(arr, i, j - 1));
}
int win1(int arr[], int len)
{
if (len == 0)
return 0;
return max(f(arr, 0, len - 1), s(arr, 0, len - 1));
}
/*递归的方法导致时间复杂度达到O(2^n),空间复杂度为O(n);
动态规划生成两个矩阵f,s,f[i][j]表示函数f(i, j)的返回值,s[i][j]表示
函数是是s(i, j)的返回值*/
int win2(int arr[], int len)
{
if (len < 1)
return 0;
vector<vector<int>> f(len, vector<int>(len, 0));
vector<vector<int>> s(len, vector<int>(len, 0));
for (int j = 0; j < len; j++)
{
f[j][j] = arr[j];
for (int i = j - 1; i >= 0; i--)
{
f[i][j] = max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);
s[i][j] = min(f[i + 1][j], f[i][j - 1]);
}
}
return max(f[0][len - 1], s[0][len - 1]);
}
int main()
{
int n;
cin >> n;
int* in = new int[n];
for (int i = 0; i < n; i++)
{
cin >> in[i];
}
int res1 = win1(in, n);
int res2 = win2(in, n);
cout << res1 << " " << res2 << endl;
getchar();
return 0;
}
跳跃游戏
题目
给定数组arr,arr[i]==k代表可从位置i向右跳1-k个距离。比如arr[2]==3,代表从位置2可以跳到位置3或4或5.如果从位置0出发,返回最少跳几次能跳到arr最后的位置上。
要求:如果arr长度为N,要求实现时间复杂度为O(N),额外空间复杂度为*O(1)*的方法。
代码
int jumpGame(int arr[], int len)
{
if (len < 1)
return -1;
int cur = 0;
int next = 0;
int step = 0;
for (int i = 0; i < len; i++)
{
if (cur < i)
{
step++;
cur = next;
}
next = max(next, i + arr[i]);
}
return step;
}
数组中的最长连续序列
题目
给定无序数组arr,返回其中最长的连续序列的长度。
代码
使用哈希表可以实现时间复杂度为O(N)、额外空间复杂度为O(N)的方法。
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
int merge(map<int, int> &mp, int less, int more)
{
int left = less - mp[less] + 1;
int right = more + mp[more] - 1;
int len = right - left + 1;
mp[left] = len;
mp[right] = len;
return len;
}
int maxConsecutive(int arr[], int len)
{
if (len < 1)
return 0;
int maxLen = 1;
map<int, int> m;
for (int i = 0; i < len; i++)
{
if (m.find(arr[i]) == m.end())
{
m.insert(pair<int, int>(arr[i], 1));
if (m.find(arr[i] - 1) != m.end())
{
int tmp1 = merge(m, arr[i] - 1, arr[i]);
maxLen = max(maxLen, tmp1);
}
if (m.find(arr[i] + 1) != m.end())
{
int tmp2 = merge(m, arr[i], arr[i] + 1);
maxLen = max(maxLen, tmp2);
}
}
}
return maxLen;
}
int main()
{
int len;
cin >> len;
int* arr = new int[len];
for (int i = 0; i < len; i++)
cin >> arr[i];
int maxLen = maxConsecutive(arr, len);
delete[] arr;
cout << maxLen << endl;
getchar();
return 0;
}