算法刷题记录(Day 12)

Surprising Strings(poj 3096)

原题链接
解题思路:对于每一个D-pair的D值,生成相应的组,并存放在set中,若发现重复,则直接退出,否则代表成功。

#include<iostream>
#include<vector>
#include<set>
#include<string>
using namespace std;
#define NMAX 80
set<string> J;
char S[NMAX];
int main(void) {
	while (1) {
		//scanf_s("%s", S);
		cin >> S;
		//cout << S << strlen(S) << endl;
		if (S[0] == '*') break;
		for (int i = 1; i <= strlen(S); i++) {
			J.clear();
			for (int j = 0; j < strlen(S); j++) {
				if (j + i < strlen(S)) {
					string a;
					a += S[j];
					a += S[j + i];
					if (J.count(a)) {
						goto WA;
					}
					else J.insert(a);
				}
			}
		}
		cout << S << " is surprising." << endl;
		continue;
	WA:
		cout << S << " is NOT surprising." << endl;
	}
}

关于string类型的研究:
C++string的常用函数总结
char[] string char* 相互转化
1.关于字符串的连接问题

	string a("shang jiao da");
	string b = "woyao";
	string c = b + a;
	string d = c.append(a);//注意append会改变原来的那个字符串的值,从而导致c和d的输出值是一样的

	cout << a << endl;  //sheng jiao da
	cout << b << endl;  // woyao
	cout << c << endl;  //woyao shang jiao da shang jiao da
	cout << d << endl;  //woyao shang jiao da shang jiao da

	char cur1 = 'a';
	string e = b + cur1; //string连接上单个的字符是没有问题的 
	cout << e << endl; //woyaoa

	char cur2 = 'b';
	string f;
	f += cur2; //会将cur2先强制转化为string类型从而避免了冲突
	f += cur1;
	cout << f << endl; //ba
	/*这种写法能过编译但是输出的g是错误的
	string g;
	g= cur1 + cur2;
	cout << g << endl;
	*/
	/*这种写法会直接报错
	string g = cur1 + cur2;
	*/
	string a = "123";
	char b[4] = "456";
	char d[4] = "123";
	string c = a + b;
	//string e = b + d; //不能使用两个char * 会报错
	cout << c << endl; //123456

2.关于初始化的问题

	string s("123456");
	/*---------------三个参数--------------*/
	string a("123456", 3, 3); //从3开始的三个字符串
	cout << a << endl;

	/*---------------两个参数--------------*/
	string b1("123456", 2); //代表的是前两个字符
	cout << b1 << endl; //12

	string b2(s, 2); //代表的是从标号为2的字符开始一直到结尾
	cout << b2 << endl;//3456

3.char[] 和string 的转化

	string a = "123";
	char b[4] = "456";
	string c = b;

	//string 转char[]只能赋值实现
	char d[4];
	d[0] = a[0];
	d[1] = a[1];
	d[2] = a[2];
	d[3] = a[3];
	//string e = b + d; //不能使用两个char * 会报错
	//或者使用
	strcpy(d,a.c_str())

	//string转char *不需要逐一赋值
	char *m= const_cast<char*>(a.c_str()); 
	cout << c << endl; //456
	cout << d << endl; //123
	cout << m << endl; //123

tip:
1.当使用cin读取一个字符串时,最后的换行符不会被读入,而且在字符串的最后会被加上一个’\0’。

Lucky and Good Months by Gregorian Calendar(poj 3393)

原题链接
读完题目后,存在如下问题:
1.最初始化的年份是什么?
2.星期数应该如何来进行计算呢?(可不可以利用天数再模上,首先应该判断是不是闰年,然后进行天数的累加)

问题一:最开始是1年1月1日,是星期六(注意这个条件题目中并没有给出,需要 根据题意进行一个推导)
问题二:累加天数然后进行模上7,需要对于一些特殊的例子进行判断
不知道为啥的WA,感觉思路上也不存在什么具体的问题

#include<iostream>
using namespace std;
int w;
int N_days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int L_days[13] = { 0,31,29,31,30,31,30,31,31,30,31,30,31 };
int S_days[13] = { 0,31,28,31,30,31,30,31,31,19,31,30,31 };
int leap(int x) {
	if (x < 1582) {
		if (x % 4 == 0) return 1;
		return 0;
	}
	else if (x == 1700) return 1;
	else {
		if (x % 4 == 0 && (x % 100 != 0) || x % 400 == 0) return 1;
		return 0;
	}
}

int cac_day(int Y, int M) {
	//计算Y年M月前的所有天数
	int res = 0;
	int* days;
	for (int i = 1; i < Y; i++) {
		if (leap(i)) res += 366;
		else res += 365;
	}
	if (leap(Y)) days = L_days;
	else days = N_days;
	for (int i = 1; i < M; i++) res += days[i];
	//特殊情况的处理
	if (Y > 1752 || (Y == 1753 && M > 3)) res -= 11;//包含特殊的1752年3月份的情况
	return res;

}
int week(int x) {
	
	if (x % 7 == 2) return 7;
	if (x % 7 == 1) return 6;
	else if (x % 7 == 0) return 5;
	else return x % 7 - 2;
	//return (x + 5) % 7;
	
}
int Glucky(int x) {
	//最后一个工作日是星期五
	int w = week(x);
	if (w >= 1 && w <= 4) return 0;
	else return 1;
}
int Ggood(int x) {
	//第一个工作日是星期1
	int w = week(x);
	if (w == 1 || w==6 || w==7) return 1;
	else return 0;

}
int main() {
	cin >> w;
	while (w--) {
		int D;
		int lucky = 0, good = 0;
		int Ys, Ms, Ye, Me;
		cin >> Ys >> Ms >> Ye >> Me;
		D=cac_day(Ys,Ms);
		for (int i = Ys; i <= Ye; i++) {
			int* days;
			if (i == 1752) days = S_days;
			else if (leap(i)) days = L_days;
			else days = N_days;
			//注意1752年9月只有19天
			
			for (int j = (i == Ys) ? Ms : 0; j <= (i==Ye?Me:12); j++) {
				//1号是第D+1天,该月最后一天为D+days[j]
				if (Glucky(D + days[j])) lucky++;
				if (Ggood(D+1)) good++;
				D += days[j];
			}
		}
		cout << lucky << " " << good << endl;
	}
}

Balance(poj 1837)

原题链接
题目类型:动态规划

思路一:dfs来进行穷举
超时警告事后分析复杂度为O(20^20),所以一定会超时的。

#include<iostream>
#include<vector>
using namespace std;
vector<int > L;
vector<int > W;
int C, G;
int res = 0;
void dfs(int left, int right, int position) {
	if (position == G) {
		if (left == right) res++;
		return;
	}
	for (int i = 0; i < L.size(); i++) {
		int cur = W[position] * L[i];
		if (cur > 0) right += cur;
		else left -= cur;
		dfs(left, right, position + 1);
		//做完dfs一定要记得恢复
		if (cur > 0) right -= cur;
		else left += cur;

	}
}
int main() {
	cin >> C >> G;
	for (int i = 0; i < C; i++) {
		int cur;
		cin >> cur;
		L.push_back(cur);
	}
	for (int i = 0; i < G; i++) {
		int cur;
		cin >> cur;
		W.push_back(cur);
	}
	dfs(0, 0, 0);
	cout << res;
}

思路二:动态规划
dp[i][j]代表的时当已经放置了第i个物品之后重量为j时的总放置数。
最大重量为7500,因此对于天平的每一个状态都进行加7500的操作,从而使得左边重的时候也能正确表示。

#include<iostream>
#include<vector>
using namespace std;
vector<int > L;
vector<int > W;
int C, G;
int res = 0;
int dp[25][15005];//代表的是当已经放入第i个物品时,此时重量为j的总的个数
int main() {
	cin >> C >> G;
	int MaxWeight = 0;
	for (int i = 0; i < C; i++) {
		int cur;
		cin >> cur;
		L.push_back(cur);
	}
	MaxWeight = L[L.size() - 1];
	for (int i = 0; i < G; i++) {
		int cur;
		cin >> cur;
		W.push_back(cur);
		MaxWeight += cur;
	}
	MaxWeight *= L[L.size() - 1];
	memset(dp, 0, sizeof(dp));
	//初始化dp数组
	for (int i = 0; i < L.size(); i++) {
		dp[0][L[i] * W[0] + 7500] = 1;
	}

	//动态规划求解
	for (int i = 1; i < W.size(); i++) {
		//对所有的重量遍历
		for (int j = -MaxWeight + 7500; j <= MaxWeight + 7500; j++) {
			dp[i][j] = 0;
			for (int k = 0; k < L.size(); k++) {
				dp[i][j] += dp[i - 1][j - (W[i] * L[k])];//注意这里不需要再加上7500了
			}
		}
	}
	cout << dp[W.size() - 1][7500];

}

总结

复杂度分析先行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值