A 二分搜索
Description
给定一个排好序的数字序列,查找某个数字是否存在这个数字序列中
Input
第一行,一个数字n代表有n个数字,0<n≤110000
第二行,n个数字,以空格分隔,已经从小到大排好顺序
接下来若干行,每行一个数字,表示查询的数字。如果数字为0,表示查询结束
Output
对于每个查询,输出一行。如果找到了,输出yes。如果没有找到,输出no。
Sample Input 1
5
2 3 5 7 9
1
2
5
10
0
Sample Output 1
no
yes
yes
no
code
#include <iostream>
using namespace std;
//在已排序(升序)数组a[left...right]中查找元素x,
//如果找到,返回x的下标;否则返回-1
int biSearch(int x, int a[], int left, int right) {
if (left > right//(第一个空) )//搜索完毕,未找到该元素
return -1;
int m = (left + right)/2;//(第二个空)//折半
if (a[m] > x) //如果中间的数字大于x,在数组左半部分递归查找
return biSearch(x, a, left, m - 1); //(第三个空)
else if (a[m] == x//(第四个空) //如果找到,直接返回位置
return m;
else //否则在数组右半部分递归查找
return biSearch(x, a, m + 1, right);//(第五个空)
}
int main() {
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++)
cin >> a[i];
int x;
cin >> x;
while (x != 0) {
if (biSearch(x, a, 0, n-1)>=0)
cout << "yes" << endl;
else
cout << "no" << endl;
cin >> x;
}
}
B 0-1背包
Description
给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。
Input
共有n+1行输入: 第一行为n值和c值,表示n件物品和背包容量c; 接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。
Output
输出装入背包中物品的最大总价值。
Sample Input 1
5 10
2 6
2 3
6 5
5 4
4 6
Sample Output 1
15
code
#include <iostream>
#include <algorithm>
using namespace std;
//利用回溯法求解0-1背包问题
struct Obj {//物品的数据结构
int weight;
int value;
};
int cv = 0, cw = 0, bestc = 0;//cv当前总价值,cw当前总重量,bestc当前最优解
int n, c;//n物品总数,c背包容量
Obj* objs;
//限界函数(严格)
float bound(int i) {
int cleft = c - cw;//背包剩余容量
int b = cv;//价值上界
while (i <= n && objs[i].weight < cleft) { //若物品i存在且重量不超过背包剩余容量
b+= objs[i].value;
cleft -= objs[i].weight;
i++;
}
if (i <= n) {
b += objs[i].value * cleft / objs[i].weight; //用物品的一部分填满背包
}
return b;
}
//递归回溯函数
void backtrack(int t) {
if (t > n//(第一个空)) {//得到问题的一个可能解
if (cv > bestc) {
bestc = cv;
}
return;
}
//如果满足约束条件,进入左子树
if (objs[t].weight + cw <= c) {//(第二个空)
cw += objs[t].weight;
cv += objs[t].value;
backtrack(t + 1);
cv -= objs[t].value;//(第三个空)
cw -= objs[t].weight;
}
//如果满足限界条件,进入右子树
if (bound(t) > bestc)// (第四个空)
backtrack(t + 1);//(第五个空)
}
//用于排序的比较函数,单位价值高的排在前面
bool cmp(Obj obj1, Obj obj2) {
if (float(obj1.value) / obj1.weight > float(obj2.value) / obj2.weight)
return true;
else
return false;
}
int main() {
int i;
cin >> n >> c;
objs = new Obj[n + 1];
for (i = 1; i <= n; i++) {
cin >> objs[i].weight;
cin >> objs[i].value;
}
sort(objs + 1, objs + n + 1, cmp);
backtrack(1);
cout << bestc;
return 0;
}
C 购书计划
Description
算法课程虽然结束了。但是小明学习算法的兴趣依然不减,他打算假期再好好地学习一下算法,提高一下自己的编程能力。老师给他推荐了一些不错的算法书单,包括《算法竞赛入门经典》、《挑战程序设计竞赛》、《数据结构与算法分析》等等。他看了看银行卡上的余额,所剩已经不多了。他打算把购买机票后剩下的钱都用来买书。小明也不打算买过于便宜的书。因为书的价格太便宜,意味着内容不够全面,大部分内容他都学过了。看着长长的书单,你能帮小明算算他最多可以买多少本书吗?
Input
第一行4个整数,分别表示小明的银行卡余额r(0 < r < 1000)、机票的价格p(0 < p < 1000)、书的最低价格b(0 < b < 1000)、书单列表长度n(0 < n < 1000)
接下来1行,n个数字,空格分隔,表示n本书的价格
Output
一个整数,表示小明买书的最多数量
Sample Input 1
500 300 30 5
80 70 90 28 118
Sample Output 1
2
Hint
输入样例:
500 300 30 5
30 40 40 30 60
输出样例:
5
输入样例:
500 450 30 5
60 70 80 80 90
输出样例:
0
输入样例:
500 300 70 5
30 50 60 40 35
输出样例:
0
code
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int r,p,b,n;
cin>>r>>p>>b>>n;
int a[1003];
for (int i =1;i<=n;i++){
cin>>a[i];
}
int m=r-p;//余额
int count=0;
for (int i=1;i<=n;i++){
if(a[i]>=b&&m>=a[i]){
m-=a[i];
count++;
}
else
break;
}
cout<<count<<endl;
return 0;
}
D 带书计划
Description
小明买到了他心仪的算法书。他打算带着这些书回家,趁着假期好好学习一下算法。但是由于飞机上有行李重量的限制,大块头的计算机书籍都很重。小明想尽可能用满行李重量的限额,在不超过限额的前提下,带的书越重越好。辛辛苦苦学了一学期算法的你,能帮助小明找到最佳的解决方案吗,告诉他可以带哪些书吗?
Input
第一行3个整数,分别代表飞机重量的限制b(0< b < 1000)、书的数量n(0 < n < 100)。
下面n行,每行一个字符串和整数,空格分隔,代表每本书的名称和重量
Output
按书名的字典排序输出多行,每行代表一本书。如果有多个答案,输出字典序最小的答案。如果一本书都不能带,输出-1
Sample Input 1
20 4 i
ntroduction_algorithm 13
algorithm_training 6
data_struct 15
beauty_of_math 4
Sample Output 1
algorithm_training
introduction_algorithm
Hint
《introduction_algorithm》《algorithm_training》和《data_struct》《beauty_of_math》两种组合都可以获得最大值,取字典序最小的按字典序输出。
code
#include <bits/stdc++.h>
using namespace std;
struct node
{
string s;
int num;
friend bool operator<(node a,node b)
{
return a.s<b.s;
}
}a[1005];
int dp[1005],pre[1005],p[1005];
string dpp[1005];
string ss[105];
int main()
{
ios::sync_with_stdio(0);
int n,m;
cin>>n>>m;
for(int i = 1; i <= m; i++)
{
string s;
int v;
cin>>s>>v;
a[i].s = s,a[i].num = v;
}
memset(dp,-1,sizeof(dp));
dp[0] = 0;
for(int i = 1; i <= n; i++)
dpp[i] = "";
sort(a+1,a+1+m);
for(int i = 1; i <= m; i++)
for(int j = n; j >= a[i].num; j--)
{
if(dp[j-a[i].num] != -1 && (dp[j] == -1 || dpp[j-a[i].num]+a[i].s < dpp[j]))
{
dp[j] = 1;
pre[j] = i;
p[j] = j-a[i].num;
dpp[j] = dpp[j-a[i].num]+a[i].s;
}
}
int mx = -1,pos = -1;
for(int i = n; i >= 1; i--)
if(dp[i] == 1){
mx = i;
break;
}
pos = pre[mx];
if(mx == -1)
{
puts("-1");
return 0;
}
else
{
int top = 0;
while(mx)
{
ss[++top] = a[pre[mx]].s;
mx -= a[pre[mx]].num;
}
for(int i = top; i >= 1; i--)
cout<<ss[i]<<'\n';
}
return 0;
}
E 学习计划
Description
今年的暑假假期为1月16日至2月27日,一共43天。小明打算利用其中的连续M天(1 ≤ M≤ 1,000)好好学习一下算法。他在中国大学MOOC、Coursera等在线课程网站选择了N门(1 ≤ N ≤ 10,000)不错的网上在线课程,但是这些课程开始的时间S、持续的天数D(1 ≤ Di ≤ M)都是不同的,最早开始时间为0。小明希望完整地选几门课程学习,并且从寒假的第一天到最后一天,每天只上一门课,并且每天有课。每门课程需要完成作业的时间为H,小明做作业的总的时间最多是T (1 ≤ T≤ 1000)。小明根据每门课程介绍的学习内容给每门课程标注了收获值。小明希望在所有课程总的作业时间不超过T的前提下,所有课程总的收获值C最大。请你帮助小明制定他的学习计划吧
Input
第一行空格分隔的三个整数,代表M、N、T
下面N行,每行空格分隔的4个数字,表示每门课程的S、D、C、H
Output
一个整数代表最大的收获值,如果找到满足约束条件的安排计划。如果没有可行计划,输出-1
Sample Input 1
5 6 10
0 2 20 6
2 3 5 6
0 1 2 1
1 1 1 3
1 2 5 4
3 2 10 2
Sample Output 1
17
Hint
选第3、5、6门课程,收获值为17、作业时间为7。如果选择前2门课程,尽管收获值为25,但是作业总时间超过了作业总时间限制10
code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
ll s,d,c,h;
friend bool operator<(node a,node b)
{
return a.s==b.s?a.d<b.d:a.s<b.s;
}
}a[10005];
vector<node> G[1005];
ll dp[1005][1005];
int main()
{
ll m,n,t;
cin>>m>>n>>t;
for(int i = 1; i <= n; i++)
{
cin>>a[i].s>>a[i].d>>a[i].c>>a[i].h;
a[i].s++;
}
sort(a+1,a+1+n);
for(int i = 1; i <= n; i++)
G[a[i].s].push_back(a[i]);
memset(dp,-1,sizeof(dp));
if(G[1].size() == 0)
{
puts("-1");
return 0;
}
dp[1][0] = 0;
for(int i = 1; i <= m; i++)
{
int k = G[i].size();
for(int j = 0; j < k; j++)
{
node b = G[i][j];
if(b.d+i > m+1)
continue;
for(int q = 0; q <= t-b.h; q++)
if(dp[i][q] != -1)
dp[b.d+i][q+b.h] = max(dp[b.d+i][q+b.h],dp[i][q]+b.c);
}
}
ll ans = -1;
for(int i = 0; i <= t; i++)
ans = max(ans,dp[m+1][i]);
printf("%lld\n",ans);
return 0;
}
/*
1 1 100
1 1 3 0
3 3 5
1 1 3 0
2 1 4 0
3 1 3 0
*/