1.题目描述:输入一个字符串,含有括号(大括号,小括号,中括号),数字和字母,数字(n)之后必跟一个括号(测试用例里的括号都是匹配的),代表括号内的字符串重复(n)次。括号里可以有嵌套,即括号里含有括号。现在将输入的字符串逆序展开;
输入描述:字符串,例:abc3(A)
输出描述:字符串,例:AAAcba
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
bool kuohao(string str)
{
if (str.find("{") != -1 || str.find("[") != -1 || str.find("(") != -1)//str.find返回值为第一次查询到的位置坐标
return true;//表示有括号
else return false;//无
}
string de(int left, int right, string str)
{
int time = (int)(str[left - 1] - '0');
string temp(str.begin() + left + 1, str.begin() + right);
for (int i = 1; i < time; ++i)
{
for (int j = 0; j < temp.size(); ++j)
str.insert(str.begin() + right + j + 1, temp[j]);//再rigt后插入数据
}
//删除
str.erase(str.begin() + right);//为了不影响顺序倒着删除
str.erase(str.begin() + left);
str.erase(str.begin() + left - 1);
return str;
}
int main()
{
string str;
while (cin >> str)
{
//首先输入判断有无大小中括号
while (kuohao(str))
{
int left;
int right;//记录坐标位置
int len = str.size();
//依次查询 { [(
if (str.find("{") != -1)//有大括号
{
left = str.find("{");
right = str.find("}", left);//这里只暂时考虑只有一位数字的情况
str = de(left, right, str);
}
else if (str.find("[") != -1)
{
left = str.find("[");
right = str.find("]", left);//这里只暂时考虑只有一位数字的情况
str = de(left, right, str);
}
else if (str.find("(") != -1)
{
left = str.find("(");
right = str.find(")", left);//这里只暂时考虑只有一位数字的情况
str = de(left, right, str);
}
}
reverse(str.begin(), str.end());
cout << str << endl;
}
return 0;
}
2.题目描述
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。
输入描述:
输入的第 1 行,为两个正整数,用一个空格隔开:N m
(其中 N ( <32000 )表示总钱数, m ( <60 )为希望购买物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q
(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)
输出描述:
输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值( <200000 )。
示例1
输入
复制
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
输出
复制
2200
#include<iostream>
#include<vector>
using namespace std;
//依赖的01背包问题 最多两个附件
int max(int a, int b)
{
return a > b?a:b;
}
int main()
{
int n, m;//n=总钱数 m=物品个数
while (cin>>n>>m)
{
n = n / 10;
vector<vector<int> > dp( m + 1, vector<int>(n + 1,0));//定义为m+1*n+1大的数组,元素为0,n/10因为单价都是10的倍数 节约空间
vector<vector<int> > value(m + 1, vector<int>(3, 0));//单件
vector<vector<int> > weight(m + 1, vector<int>(3, 0));//单价*重要程度
int v, p, q;//价格,重要程度,主件/附件
for (int i = 1; i <= m; ++i)//存入所有信息
{
cin >> v >> p >> q;
v /= 10;
p = v * p;
if (q == 0)//主件
{
value[i][0] = v;
weight[i][0] = p;
}
else if (value[q][1]==0)
{
value[q][1] = v;
weight[q][1] = p;
}
else
{
value[q][2] = v;
weight[q][2] = p;
}
}
//开始动态规划
for (int i = 1; i <=m; ++i)
{
for (int j = 1; j <=n ; ++j)
{
dp[i][j] = dp[i - 1][j];//如果不放入
if (value[i][0] >0)
{
if (value[i][0] <= j)//价格不超过
{
int t = max(dp[i][j], dp[i - 1][j - value[i][0]] + weight[i][0]);//比较放入与不放入谁的值更大
dp[i][j] = t;
}
if (value[i][0] + value[i][1] <= j)//价格不超过
{
int t = max(dp[i][j], dp[i - 1][j - value[i][0] - value[i][1]] + weight[i][0] + weight[i][1]);//比较放入与不放入谁的值更大
dp[i][j] = t;
}
if (value[i][0] + value[i][1] + value[i][2] <= j)//价格不超过
{
int t = max(dp[i][j], dp[i - 1][j - value[i][0] - value[i][1] - value[i][2]] + weight[i][0] + weight[i][1] + weight[i][2]);//比较放入与不放入谁的值更大
dp[i][j] = t;
}
}
}
}
cout << dp[m][n]*10 << endl;;
}
return 0;
}
3.动态规划 最长递增子串
题目描述
Redraiment是走梅花桩的高手。Redraiment总是起点不限,从前到后,往高的桩子走,但走的步数最多,不知道为什么?你能替Redraiment研究他最多走的步数吗?
样例输入
6
2 5 1 5 4 5
样例输出
3
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int num;
while (cin>>num)
{
vector<int> a(num);
vector<int> dp(num, 1);
for (int i = 0; i < num; ++i)
cin >> a[i];
int max = 0;
for (int i = 1; i < num; ++i)
for (int j = 0; j < i; ++j)
{
if (a[i]>a[j] && dp[i] < dp[j] + 1)
dp[i] = dp[j] + 1;
if (max < dp[i])
max = dp[i];
}
cout << max << endl;
}
return 0;
}
4.匈牙利算法
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数N(N≤100),表示待挑选的自然数的个数。后面给出具体的数字,范围为[2,30000]。
输出:
输出一个整数K,表示你求得的“最佳方案”组成“素数伴侣”的对数。
输入:4
2 5 6 13
输出:2
解题思路:
本文采用图论中的匈牙利算法。因为 偶数+偶数=偶数
奇数+奇数=奇数
偶数+奇数=奇数
且所有的偶数不是素数,因此只对奇数进行判断
所以,将输入的数分为偶数(even,代码中打错了= =)与奇数(odd)两组。
用pick[]存放下even+odd之和是否为素数的结果
用x[]存放odd中的数据是否匹配。-1=未匹配 1=匹配
用y[]存放odd中与even中匹配数的索引
本程序的思想是对even中的数进行历遍,并且每一次都假设odd中的数据没有匹配成功(初始x[],但是不改变y[])
// 利用匈牙利算法
#include<iostream>
#include<vector>
using namespace std;
bool isprime(int a)
{
for (int i = 2; i*i <= a; ++i)
{
if (a%i == 0)
return false;
}
return true;
}
bool f(int index, vector<int> &x, vector<int> &y, vector< vector<int> > pick)
{
for (int j = 0; j < x.size(); ++j)
{
if (pick[index][j] == 1 && x[j] == -1)
{
x[j] = 1;//表示匹配
if (y[j] == -1 || f(y[j],x,y,pick) )//如果odd中的数已经匹配,将其强行占领
{//寻找与之匹配的even是否还要其他odd匹配
y[j] = index;
return true;
}
}
}
return false;
}
int main()
{
int n;
while (cin >> n)
{
/*vector<int> num(n);
for (int i = 0; i < n; ++i)
cin >> num[i];*/
//将输入的数分为偶数、奇数两部分 偶数+奇数=奇数
//排除掉:偶数+偶数=偶数 奇数+奇数=偶数 偶数不可能为素数
vector<int> enve;//偶数
vector<int> odd;//奇数
int temp;
for (int i = 0; i < n; ++i)
{
cin >> temp;
if (temp % 2 == 0)
enve.push_back(temp);
else
odd.push_back(temp);
}
//构建出偶数与奇数的关系
vector< vector<int> > pick(enve.size(), vector<int>(odd.size()));
for (int i = 0; i < enve.size(); ++i)//为质数,初始化列表
{
for (int j = 0; j < odd.size(); ++j)
{
if (isprime(enve[i] + odd[j]))//和是否为素数
{
pick[i][j] = 1;//表示和为素数
}
else
pick[i][j] = 0;
}
}
int len1 = enve.size();
int len2 = odd.size();
int count = 0;
//vector<int> x(enve.size(), -1);//-1无匹配
vector<int> y(odd.size(), -1);//-1无匹配
for (int i = 0; i < len1; ++i)
{
vector<int> x(odd.size(), -1);//每一次历遍先假设-1无匹配
if (f(i, x, y, pick))
count++;
}
cout << count << endl;
}
return 0;
}
5.有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问每个月的兔子总数为多少?
输入:9 输出:34
法一:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int month;
while (cin>>month)
{
int a=0;//三个月大
int b=0;//两个月
int c=1;//一个月
while (--month)
{
a += b;
b = c;
c = a;
}
cout << a + b + c << endl;
}
return 0;
}
法二:递归
#include<iostream>
#include<cstdio>
using namespace std;
int f(int month)
{
//思路推导:
//时间轴(月):1 2 3 4 5 6 7
// 兔子数量: 1 1 2 3 5 8 13
//发现是一个斐波那契数列,所以公式为f(n) = f(n - 1) + f(n - 2);
int ans ;
if (month == 1||month==2)
return ans = 1;
else
ans = f(month - 1) + f(month - 2);
return ans;
}
int main()
{
int month;
while (cin>>month)
{
int ans = f(month);
cout << ans;
}
return 0;
}