考研机试题 -- 字符串、背包、枚举

目录

      • 首字母大写(字符串)
      • 日志排序(字符串,双关键字排序)
      • 字符串转换整数(字符串)
      • 点菜问题(01背包)
      • 神奇的口袋(01背包,计数)
      • 整数拆分(完全背包,计数)
      • CCF201512-2 消除类游戏(枚举)

首字母大写(字符串)

https://www.noobdream.com/DreamJudge/Issue/page/1240/
如何读入一行字符串(getline),如何分开每个单词,如何转大写(toupper)

#include 
#include 
using namespace std;

int main() {
	string s;
	getline(cin, s);
	
	for(int i = 0; i < s.length(); i ++) {
		if(i == 0 || s[i - 1] == ' ')
			cout << (char)toupper(s[i]);
		else
			cout << s[i];	
	}
	return 0;
}

日志排序(字符串,双关键字排序)

https://www.noobdream.com/DreamJudge/Issue/page/1227/
双关键字排序,如何分割字符串(stringstream),如何从一个字符串中读数据(sscanf)

#include 
#include 
#include 
#include 
#include 
using namespace std;

const int N = 10010;
int n;

struct log {
	string s; //原始数据 
	string t1; //开始执行时间 
	double time; //消耗时间 
	
	bool operator < (const log &w) const {
		if(time != w.time) return time < w.time;
		else return t1 < w.t1;
	}
	
} logs[N];

int main() {
	string s;

	while(getline(cin, logs[n].s) && logs[n].s.length() != 0) {
		stringstream ssin(logs[n].s);
		string str1, str2, str3, str4;
		ssin >> str1 >> str2 >> str3 >> str4;
		logs[n].t1 = str2 + str3; //年月日和时分秒合并 
		sscanf(str4.c_str(), "%lf(s)", &logs[n].time); //提取浮点数	
		n ++;
	}
	
	sort(logs, logs + n);
	
	for(int i = 0; i < n; i ++)
		cout << logs[i].s << endl; 
	return 0;	
}

stringstream的用法:

#include
string str[3];
string s = "aa bb cc";
stringstream ss(s);
ss >> str[0] >> str[1] >> str[2];

sscanf的用法:注意sscanf第一个参数是char数组

string s = "1234.5678abcd";
double a;
sscanf(s.c_str(), "%lf", &a);

字符串转换整数(字符串)

https://www.acwing.com/problem/content/3507/

#include 
#include 
#include 
#include 
using namespace std;

int main() {
	string s;
	cin >> s;
	bool flag = false;
	long long LL = 0; //记得初始化
	 
	for(int i = 0; i < s.length(); i ++) {
		if(isdigit(s[i])) {
			flag = true;
			LL = LL * 10 + (s[i] - '0'); //易错,s[i]要减去'0' 
			if(LL > INT_MAX) { //INT_MAX在cmlits头文件,int最大值2^31-1
				flag = false;
				break;
			}
			if(!isdigit(s[i + 1])) {
				break;
			}
		}
	}
	
	if(flag) cout << LL; 
	else cout << -1;
	
	return 0;
} 

法二:不用flag,当for循环发现第一个数字时,用while循环找出完整的整数

#include 
#include 
#include 
#include 
using namespace std;

int main() {
	string s;
	cin >> s;
	 
	for(int i = 0; i < s.length(); i ++) {
		if(isdigit(s[i])) {
			long long LL = 0;
			while(i < s.length() && isdigit(s[i])) {
				LL = LL * 10 + (s[i] - '0');
				if(LL > INT_MAX) {
					cout << -1;
					return 0;
				}
				i ++;
			}
			cout << LL;
			return 0;
		}
	}
	cout << -1;
	
	return 0;
} 

点菜问题(01背包)

https://www.noobdream.com/DreamJudge/Issue/page/1247/
f[i][j]表示从前 i 个物品中任选,总重量不超过 j 的集合,其属性为最大价值

#include 
using namespace std;

const int N = 1010;
int c, n, v[N], p[N], f[N][N];

int main() {
	cin >> c >> n;
	for(int i = 1; i <= n; i ++)
		cin >> p[i] >> v[i];
		
	for(int i = 1; i <= n; i ++) {
		for(int j = 0; j <= c; j ++) {
			f[i][j] = f[i - 1][j];
			if(j >= p[i]) 
				f[i][j] = max(f[i][j], f[i - 1][j - p[i]] + v[i]);
		}
	}
	
	cout << f[n][c];
	return 0;	
}

优化为一维数组:

#include 
using namespace std;

const int N = 110;
int c, n, v[N], p[N], f[N];

int main() {
	cin >> c >> n;
	for(int i = 1; i <= n; i ++)
		cin >> p[i] >> v[i];
		
	for(int i = 1; i <= n; i ++) {
		for(int j = c; j >= p[i]; j --) {
			f[j] = max(f[j], f[j - p[i]] + v[i]);
		}
	}
	
	cout << f[c];
	return 0;	
}

神奇的口袋(01背包,计数)

https://www.noobdream.com/DreamJudge/Issue/page/1242/
f[i][j]表示从前 i 个物品中任选,总重量恰好为 j 的集合,其属性为方案数
划分成两个子集合:选 i 和不选 i;f[i][j]等于两个子集合的方案数相加,即f[i][j] = f[i - 1][j] + f[i - 1][j - wi]

#include 
using namespace std;

const int N = 50;
int n, f[N][N], w[N];

int main() {
	cin >> n;
	for(int i = 1; i <= n; i ++)
		cin >> w[i];
		
	f[0][0] = 1; //f[0][0]需要初始化成1。因为什么i=0表示都不选,此时总重量恰好为1,这也是一种方案
	for(int i = 1; i <= n; i ++) {
		for(int j = 0; j <= 40; j ++) {
			f[i][j] = f[i - 1][j];
			if(j >= w[i])
				f[i][j] += f[i - 1][j - w[i]];
		}
	}
	
	cout << f[n][40];
	return 0;
}

整数拆分(完全背包,计数)

https://www.noobdream.com/DreamJudge/Issue/page/1158/
每个2^n当作物品,1、2、4、8、16…为每个物品的重量。每个数可以选无限次(完全背包)
f[i][j]表示前 i 个物品任选,总体积恰好为 j 的总方案数

注意:此题使用二维数组会爆内存,因此要优化为一维数组

//原始解法:使用二维数组
#include 
using namespace std;

const int N = 1e6 + 10, MOD = 1e9;

int n, f[10000][10000], w[N];

int main() {
	cin >> n;
	w[1] = 1;
	for(int i = 2; i <= n; i ++) { //将所有2次幂保存在w中
		w[i] = w[i - 1] * 2;
	}
			
	f[0][0] = 1;
	for(int i = 1; i <= n; i ++) {
		for(int j = 0; j <= n; j ++) {
			f[i][j] = f[i - 1][j];
			if(j >= w[i])
				f[i][j] = f[i][j] + f[i][j - w[i]];
		}
	}
	
	cout << f[n][n];
	return 0;
}

优化为一维数组:

#include 
using namespace std;

const int N = 1e6 + 10, MOD = 1e9;

int n, f[N];

int main() {
	cin >> n;

	f[0] = 1;
	for(int i = 1; i <= n; i *= 2) {
		for(int j = i; j <= n; j ++) {
			f[j] = (f[j] + f[j - i]) % MOD;
		}
	}
	
	cout << f[n];
	return 0;
}

CCF201512-2 消除类游戏(枚举)

https://blog.csdn.net/qq_51800570/article/details/122933824

#include 
#include 
using namespace std;

const int N = 40;
int n, m, a[N][N], b[N][N];

int main() {
	cin >> n >> m;
	for(int i = 0; i < n; i ++)
		for(int j = 0; j < m; j ++)
			cin >> a[i][j];
			
	memset(b, 0, sizeof b);
	
	//按行枚举 
	for(int i = 0; i < n; i ++) {
		for(int j = 1; j < m - 1; j ++) {
			if(a[i][j] == a[i][j - 1] && a[i][j] == a[i][j + 1]) {
				b[i][j - 1] = 1;
				b[i][j] = 1;
				b[i][j + 1] = 1;
			}
		}
	}		
	//按列枚举
	for(int j = 0; j < m; j ++) {
		for(int i = 1; i < n - 1; i ++) {
			if(a[i][j] == a[i - 1][j] && a[i][j] == a[i + 1][j]) {
				b[i - 1][j] = 1;
				b[i][j] = 1;
				b[i + 1][j] = 1;
			}
		}
	}	
	
	for(int i = 0; i < n; i ++) {
		for(int j = 0; j < m; j ++) {
			if(b[i][j] == 1) cout << 0 << " ";
			else cout << a[i][j] << " ";
		}	
		cout << endl;
	}
	
	return 0;
} 

你可能感兴趣的:(考研,算法)