暴力枚举-习题篇

习题10-1:(洛谷P3392)涂国旗

#include <iostream>
using namespace std;
char a[55][55];
int n, m;
int play(int t,int r) {
	int num = 0;
	for (int i = 1; i <= t; i++) {
		for (int j = 1; j <= m; j++) {
			if (a[i][j] != 'W') num++;
		}
	}
	for (int i = t + 1; i <= r - 1; i++) {
		for (int j = 1; j <= m; j++) {
			if (a[i][j] != 'B') num++;
		}
	}
	for (int i = r; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (a[i][j] != 'R') num++;
		}
	}
	return num;
}
int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
		}
	}
	int min = 2505;
	for (int i = 1; i <= n-2; i++) {
		for (int j = i + 2; j <= n; j++) {
			if (play(i, j) < min) min = play(i, j);
		}
	}
	cout << min;
	return 0;
}

 通过枚举关键的要素找到突破口,枚举边界线,t为白色最后一行,r为红色第一行。

习题10-2:(洛谷P3654)First Step

#include <iostream>
using namespace std;
char a[220][220];
int main() {
	int n, m,z,ans=0,num=0;
	cin >> n >> m>>z;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
			if (a[i][j] == '.') num++;
		}
	}
	if (z != 1) {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m - 1; j++) {
				int flag = 1;
				for (int c = 0; c <= z - 1; c++) {
					if (a[i][j + c] != '.') {
						flag = 0;
					}
				}
				if (flag == 1) ans++;
			}
		}

		for (int j = 1; j <= m; j++) {
			for (int i = 1; i <= n - 1; i++) {
				int flag = 1;
				for (int c = 0; c <= z - 1; c++) {
					if (a[i + c][j] != '.') {
						flag = 0;
					}
				}
				if (flag == 1) ans++;
			}
		}
	}
	else {
		ans = num;
	}

	cout << ans;
	return 0;
}

需要注意的是,数组不能开110*110,因为100+100在代码中是可能发生的。

习题10-3:(洛谷P1217)回文质数

标答:

#include <iostream>
using namespace std;
bool reflush(int n) {
	int a[15];
	int x = 0;
	while (n) {
		a[x++] = n % 10;
		n /= 10;
	}
	int flag = 1;
	for (int i = x - 1, j = 0; i >= j; i--, j++) {
		if (a[i] != a[j]) {
			flag = 0;
			break;
		}
	}
	return flag;
}
bool check(int n) {
	int sym = 1;
	if (n < 2) {
		return 0;
	}
	else {
		for (int i = 2; i * i <= n; i++) {
			if (n % i == 0) {
				sym = 0;
				break;
			}
		}
	}
	return sym;
}
int main() {
	int a, b;
	cin >> a >> b;
	for (int i = a; i <= b; i++) {
		if (i % 2 != 0&&i>=5) {
			if (reflush(i) && check(i)) {
				cout << i << endl;
			}
		}
	}
	return 0;
}

1亿=1*10的8次方,测试点应该不会超过这个数据,因此没有判断,加上判断也可以。

另法:

for (d1 = 1; d1 <= 9; d1+=2) {    // 只有奇数才会是素数
     for (d2 = 0; d2 <= 9; d2++) {
         for (d3 = 0; d3 <= 9; d3++) {
           palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
         }
     }
 }

请根据此算法自行编程。

习题10-4:(洛谷P1149)火柴棒等式

#include <iostream>
using namespace std;
//6 2 5 5 4 5 6 3 7 6
typedef struct number {
	int num;
	int firerod;
}Num;
Num a[10];
int reflush(int n) {
	if (n!= 0) {
		int m = n;
		int b[6] = { 0 };
		int x = 0;
		int sum = 0;
		int num0 = 0;
		while (n) {
			b[++x] = n % 10;
			n /= 10;
			sum += a[b[x]].firerod;
		}
		return sum;
	}
	else {
		return 6;
	}
	
}
int main() {
	int n1,ans=0;
	cin >> n1;
	for (int i = 0; i <= 9; i++) {
		a[i].num = i;
		switch (i) {
		case 0:a[i].firerod = 6; break;
		case 1:a[i].firerod = 2; break;
		case 2:a[i].firerod = 5; break;
		case 3:a[i].firerod = 5; break;
		case 4:a[i].firerod = 4; break;
		case 5:a[i].firerod = 5; break;
		case 6:a[i].firerod = 6; break;
		case 7:a[i].firerod = 3; break;
		case 8:a[i].firerod = 7; break;
		case 9:a[i].firerod = 6; break;
		}
	}
	for (int i = 0; i <=1111; i++) {
		for (int j = 0; j <=1111; j++) {
			if (reflush(i) + reflush(j) + reflush(i + j) + 4 == n1)
				ans++;
		}
	}
	cout << ans;
	return 0;
}

经验启示:

1.函数调用后无论如何先保存传入的参数,防止后期该数据了还用改后的当没改前的

2.数组这里没必要开1000,然后用a[m].firerod保存sum,多此一举且占运行时间,导致无法通过。

习题10-5:(洛谷P3799)妖梦拼木棒

#include <iostream>
using namespace std;
#include <algorithm>
int m;
unsigned long long bucket[5005];//计数桶
int main() {
	int n;
	cin>> n;
	int maxn = 0;
	unsigned long long sum = 0;
	for (int i = 0; i < n; i++) {
		cin >> m;
		bucket[m]++;
		maxn = max(m, maxn);
	}
	for (int i = 2; i <= maxn; i++) {
		if (bucket[i] >= 2) {
			for (int c = 1; c <=i/2; c++) {
				if (c == i - c) {
					sum += bucket[i] * (bucket[i] - 1) / 2 * bucket[c] * (bucket[c] - 1) / 2;
				}
				else {
					sum += bucket[i] * (bucket[i] - 1) / 2 * bucket[c] * bucket[i-c];
				}
			}
		}
	}
	cout << sum % (1000000000 + 7);
	return 0;
}

注意要点:

1.确定数据范围很重要:1<i<=maxn  1<=c<=i-c<i 

以此来确定循环的范围,如果c是从1递增到i,那么这个题就会有很多次无效的重复。

2.枚举元素的选择很重要,枚举木棒的长度就是一个优解,而如果用数组保存输入木棒的长度,一方面要开一个很大的数组,另一方面枚举木棒长度不方便简洁。

3.本题思路:

先选两根长度为m的木棒,方案数为组合数c(am,2),am代表长度为m木棒的个数。

再选两根和为m的木棒,(1)i=m-i,方案数为c(am/2,2)

(2)i≠m-i,方案数为c(ai,1)*c(am-i,1)

4.注意不要枚举两个变量i,j,然后判断他们和是否是m,这样会增大运算量,这里单重循环就可以解决问题。m-i不存在那么其方案数表达式就是0不用担心。

习题10-7:(洛谷P2036)Perket

思路:

本题为子集枚举算法。

各个配料被选取为1,否则为0.

从1到全集枚举(从1不从0是因为至少有一个配料被选取),判断单配料是否被选取,如果被选取就更新总酸度和总苦度,通过打擂台的方式确定最小差。不要忘记每次重置总酸度和总苦度。

#include <iostream>
using namespace std;
#include <cmath>
typedef struct element {
	int suan;
	int ku;
}E;
E a[15];
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].suan >> a[i].ku;
	}
	int multiple_suan = 1;
	int sum_ku = 0;
	int U = 1 << n;//U-1为全集
	long long min = 10000000000;
	for (int i = 1; i < U; i++) {
		multiple_suan = 1;
		sum_ku = 0;
		for (int j = 1; j <= n; j++) {
			if (1 << j - 1 & i) {
				multiple_suan *= a[j].suan;
				sum_ku += a[j].ku;
			}
		}
		if (abs(multiple_suan - sum_ku) < min) {
			min = abs(multiple_suan - sum_ku);
		}
	}
	cout << min;
	return 0;
}

习题10-8:(洛谷P1433)吃奶酪

思路:

本题为排列枚举算法。

设初始的原点为点0,order[0]为0,

之后排列枚举各个点的顺序,从而解决问题。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
typedef struct dot {
	double x;
	double y;
}D;
D a[20];
int order[20];
double xy(int m,int n) {
	return sqrt(pow(a[m].x - a[n].x, 2) + pow(a[m].y - a[n].y, 2));
}
int main() {
	int n;
	cin >> n;
	a[0].x = 0;
	a[0].y = 0;
	order[0] = 0;
	int last = 0;
	double sum = 0;
	double min = 100000;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].x >> a[i].y;
		order[i] = i;
	}
	do {
		sum = 0;
		last = 0;
		for (int i = 1; i <= n; i++) {
			int j;
			for (j = 1; j <= n; j++) {
				if (order[j] == i) {
					sum += xy(last, j);
					break;
				}
			}
			last = j;
		}
		if (sum < min) min = sum;
	} while (next_permutation(order+1,order+n+1));
	printf("%.2f", min);
	return 0;
}

注意:本算法无误,但是复杂度不够好,只能过50分,现阶段用暴力枚举只能这样了。n<10以内的数据没问题。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值