蓝桥杯备赛-暴力枚举专题

今天的专题是暴力枚举

蓝桥杯又名暴力杯,懂的都懂;主要是一些二进制枚举,在数据范围不大的时候可以用到,也可以骗分,当前不写二进制枚举,写暴搜更好(因为本人暴搜搜不明白)

T1:费解的开关

9b674a6a5de4428b98fefc8c16251fb0.png

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111
3
2
-1

解题思路:

我们可以发现,想要是全部灯打开,当第一行灯泡的状态的确定了,我们就可以通过变化第二行灯泡的状态来使第一行全亮,操作第3行又可以使第二行全亮。。。

一直递推下去,最后只要检查

1.步数是否合法

2.最后一行是否全亮(在此之间前4行一定为全亮)

所以我们枚举第一行的状态即可,2^5 = 32种状态

代码

// 思路:第一行确定了就确定了,枚举第一行的所有情况
//       然后向下递推
//       每一种情况验证:1.是否最后一行全被点亮
//                      2.是否在6步之内
#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

const int N = 1e5 + 50;
char a[6][6]; // 存图
char backup[6][6]; // 备份数组
int dx[] = {0,0,0,-1,1},dy[] = {0,-1,1,0,0};
void turn(int x,int y) { // 转换该点四周
	a[x][y] ^= 1; // 先反转自己
	for (int i = 1;i <= 4; i++) {
		int nx = x + dx[i],ny = y + dy[i];
		if (nx < 0||nx > 4 ||ny < 0 ||ny > 4) continue;
		a[nx][ny] ^= 1;
	}
}
void solve() {
	int min_steps = 1e9; // 最小步数

	for (int i = 0;i < 5; i++) 
		for (int j = 0;j < 5; j++)
		cin >> a[i][j];

	for (int op = 0;op < 1<<5; op++) { // 枚举第一行的所有情况-2^5种
		int steps = 0; // 记录步数
		memcpy(backup,a,sizeof a); // 拷贝
		for (int j = 0;j < 5; j++) {
			if ((op >> j) & 1) { // 当前点要转换
				steps++; // 记录步数
				turn(0,j); // 转换
			}
		}
		for (int i = 0;i < 4; i++) { // 处理中间三行
			for (int j = 0;j < 5; j++) {
				if (a[i][j] == '0') { // 对于一个灭的灯泡,通过它正下方的灯泡来点亮它
					steps++;
					turn(i + 1,j);
				}
			}
		}
		int f = 1;
		// 判断1:最后一行是否全部点亮
		for (int j = 0;j < 5 ;j++) {
			if (a[4][j] == '0') {
				f = 0;
				break;
			}
		}
		if (f) min_steps = min(min_steps,steps);
		memcpy(a,backup,sizeof a); // 拷贝回来
	} 
	if (min_steps > 6) cout << "-1" << '\n';
	else cout << min_steps << '\n';
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t; cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

T2:飞行员兄弟

718621599a444b1a96b938f2196be819.png

-+--
----
----
-+--
6
1 1
1 3
1 4
4 1
4 3
4 4

解题思路:

该题和上一题类似,但是该题要记录操作,以及是枚举16个把手的状态,找最小操作次数

代码

// 这题和费解的开关有异曲同工之妙
// 费解的开关是枚举第一行的状态,该题则可直接枚举16个把手的状态
// O(6e4)的时间复杂度,不会超时
#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

const int N = 1e5 + 50;
char a[5][5]; // 存原图
char backup[5][5];
void turn(int x,int y) {
	for (int j = 1;j <= 4; j++) { // x行
		a[x][j]=='+'?a[x][j]='-':a[x][j]='+';
	}
	for (int i = 1;i <= 4; i++) { // y列
		a[i][y]=='+'?a[i][y]='-':a[i][y]='+';
	}
	a[x][y]=='+'?a[x][y]='-':a[x][y]='+';
}
void solve() {
	vector<pair<int,int> > ans; // 记录操作
	for (int i = 1;i <= 4; i++) 
		for (int j = 1;j <= 4; j++) 
			cin >> a[i][j];
	for (int op = 0;op < 1<<16; op++) { // 枚举2^16种状态
		vector<pair<int,int> > res;
		memcpy(backup,a,sizeof a);  // 拷贝
        // 进行操作
        for (int i = 0;i < 16; i++) {
        	if ((op >> i) & 1) {
        		int x = i / 4 + 1,y = i % 4 + 1;
        		res.push_back({x,y});
        		turn(x,y);
        	}
        } 
		bool flag = true;
		for (int i = 1;i <= 4; i++) {
			for (int j = 1;j <= 4; j++) {
				if (a[i][j] == '+') {
					flag = false;
					break;
				}
			}
		}
		// 开始时,ans.size()==0,一定要特判一下
		if (flag && (ans.size() == 0 || res.size() < ans.size())) { // 寻找更优解
			ans = res;
		}
        memcpy(a,backup,sizeof a);  // 拷贝
	}
	cout << ans.size() << '\n';
	for (auto x:ans) {
		cout << x.f << " " << x.s << '\n';
	}
	return ;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

T3:本题又主要考察了贪心(24牛客暑假训练营1)

c4da1fa5d9a94cc793e82d195129e8f4.png

3
4 3
2 4 5 8
1 2
1 4
2 4
3 1
3 1 1
2 3
6 6
1 2 3 4 5 6
2 3
2 3
3 4
4 5
5 6
6 1
1
1
4

解题思路

可以看到其中m<=10,最多有10场比赛,对于每一场比赛,要么是双方其中一者赢,要么是平局,我们枚举每一场比赛的状态,得到合法解的最优解,思路和上面两题相同,更难一些;

代码

#include <bits/stdc++.h>
#define int long long
#define f first 
#define s second
using namespace std;

const int N = 1e5 + 50;
int backup[150];
void solve() {
    int ans = 100000;
    int n,m; cin >> n >> m;
    int a[n + 1]; // 存原始分
    int m1 = 0;
    vector<pair<int,int> >b(m + 1); // 存操作
    vector<pair<int,int> >c(m + 1);
    for (int i = 1;i <= n; i++) cin >> a[i];
    for (int i = 0;i < m; i++) {
        cin >> b[i].f >> b[i].s;
        // 1.预处理有1的情况
        if (b[i].f == 1 || b[i].s == 1) a[1]+=3;
        // 没有1的数据存入c中,m1为数据个数
        else c[++m1].f = b[i].f,c[m1].s = b[i].s;
    }
    for (int op1 = 0;op1 < 1<<m1; op1++) { // 0:加3   1: 加1
        for (int op2 = 0;op2 < 1<<m1; op2++) { // 0:3分加给u,1:3分加给v
            memcpy(backup,a,sizeof a); // 备份
            for (int j = 0;j < m1; j++) {
                // 2.都加1分
                if (op1 & (1<<j)) { // 为1
                    a[c[j+1].f]++,a[c[j+1].s]++;
                }
                // 3.其中一人加3分
                else {
                    if (op2 & (1<<j)) a[c[j+1].s] += 3;
                    else a[c[j+1].f] += 3;
                }
            }
            // 取最靠前排名
            int x = a[1];
            sort(a + 1,a + n + 1,greater<int>());
            for (int i = 1;i <= n; i++) {
                if (a[i] == x) {
                    ans = min(ans,i);
                    break;
                }
            }
            memcpy(a,backup,sizeof a); // 复制回来
        }
    }
    cout << ans << '\n';
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
    int t; cin >> t;
    while (t--) {
        solve();
    }
	return 0;
}

其实更简单的是写暴搜,可自行尝试(doge)

T4:心绪的解剖(24牛客寒假训练营6)

2a6d32c900b84c0782e363278cee22e5.png

5
5
10
15
20
25

0 0 5
2 0 8
5 5 5
2 5 13
21 1 3

解题思路

预处理 + 枚举 + 剪枝

初看是一个很难得题:范围1e9这怎么枚举啊?

但是注意斐波那契的增长数组是非常快的,1e9大概是它的40项左右,所以我们完全可以直接枚举3个数a,b,c,如果和为斐波那契,将三个数和数的和存入一个map中,预处理完直接离线查询即可;

o(40*40*40)的时间复杂复,稍微要加一些剪枝

代码

#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

const int N = 1e5 + 50;
struct node {
    int x,y,z;
};
int fibo[100];
map<int,node>mp;
int cnt;
void init() { // 初始化斐波那契
    fibo[0] = 0;
    fibo[1] = 1,fibo[2] = 1;
    for (int i = 3;; i++) {
        fibo[i] = fibo[i - 1] + fibo[i - 2];
        if (fibo[i] > 1e9) {
            cnt = i;
            break;
        }
    }
}
void solve() {
	init();
    for (int i = 0;i <= cnt; i++) { // 预处理
        for (int j = 0;j <= cnt; j++) {
            if (fibo[i] + fibo[j] > 1e9) break;
            for (int k = 0;k <= cnt; k++) {
                int sum = fibo[i] + fibo[j] + fibo[k];
                if (sum > 1e9) break;
                mp[sum] = {fibo[i],fibo[j],fibo[k]};
            }
        }
    }
    int q; cin >> q;
    // 离线查询
    while (q--) {
        int n; cin >> n;
        if (!mp.count(n)) {
            cout << "-1" << '\n';
        }
        else cout << mp[n].x << " " << mp[n].y << " " << mp[n].z << '\n';
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}

T5:带分数(第四届蓝桥杯)

6959f0e5bcf34ddda9f7cce820416edc.png

 输入1

100

 输出1

11

 输入2

105

 输出2

6

 解题思路

由于式子的右边一定由1~9的排列组成,所以我们可以直接计算出1~9的所有排列情况,然后枚举两个断点,使得整个排列分为三段,分别为a,b,c,在判断是否为合法的答案,记录合法答案个数即可

注意:

  1. x = a + b / c,可能出现无法整除但是int自动向下取整的情况,所以不能用除法算式来判断两边同乘c   =>   x * c = a * c + b
  2. 求全排列可以用dfs和next_permutation全排列函数

代码

dfs

// x = a + b / c,我们尝试1-9的所有全排列,然后枚举两个点将其分为三段
// n * c = b  + a * c
// 带入表达式是否成立

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 50;
int x; // 目标数
bool st[10];
int a[10]; // 记录全排列数组
int ans = 0; // 记录答案
int cal(int l,int r) {
	int res = 0;
	for (int i = l;i <= r; i++) {
		res = res * 10 + a[i];
	}
	return res;
}
void dfs(int cnt) {
	if (cnt == 10) {
		// 枚举两个断点 [1,l][l+1,r][r+1,9]
		for (int l = 1;l <= 7; l++) {
			for (int r = l + 1;r <= 8; r++) {
				int a = cal(1,l);
				int b = cal(l + 1,r);
				int c = cal(r + 1,9);
				if (x*c == a*c + b) ans++;
			}
		}
		return ;
	}
	for (int i = 1;i <= 9; i++) {
		if (st[i]) continue;
		a[cnt] = i;
		st[i] = true;
		dfs(cnt + 1);
		st[i] = false; // 回溯
	}
	return ;
}
void solve() {
	cin >> x;
	dfs(1);
	cout << ans;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t = 1;
	while (t--) {
		solve();
	}
	return 0;
}

函数

// x = a + b / c,我们尝试1-9的所有全排列,然后枚举两个点将其分为三段
// n * c = b  + a * c
// 带入表达式是否成立

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 50;
int x; // 目标数
bool st[10];
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int ans = 0; // 记录答案
int cal(int l,int r) {
	int res = 0;
	for (int i = l;i <= r; i++) {
		res = res * 10 + a[i];
	}
	return res;
}
void solve() {
	cin >> x;
	do {
		for (int l = 1;l <= 7; l++) {
			for (int r = l + 1;r <= 8; r++) {
				int a = cal(1,l);
				int b = cal(l + 1,r);
				int c = cal(r + 1,9);
				if (x * c == a * c + b) ans++;
			}
		}
	}while(next_permutation(a + 1,a + 10));
	cout << ans;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t = 1;
	while (t--) {
		solve();
	}
	return 0;
}

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis-Plus 是一个优秀的 MyBatis 增强工具,在实际开发中我们经常需要使用枚举类型来表示一些常量,如订单状态、性别等。而 MyBatis-Plus 对枚举类型的处理也非常方便,下面我来介绍一下如何使用 MyBatis-Plus 枚举字段映射。 1. 定义枚举类型 首先我们需要定义一个枚举类型,如下所示: ```java public enum StatusEnum { ENABLE(1, "启用"), DISABLE(0, "禁用"); private Integer value; private String desc; StatusEnum(Integer value, String desc) { this.value = value; this.desc = desc; } public Integer getValue() { return value; } public String getDesc() { return desc; } } ``` 2. 实体类中使用枚举类型 在实体类中使用枚举类型,如下所示: ```java public class User { private Long id; private String name; private StatusEnum status; // getter 和 setter 略 } ``` 3. 数据库表中使用枚举字段 在数据库表中使用枚举字段,如下所示: ```sql CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `status` tinyint(4) NOT NULL COMMENT '状态:1=启用,0=禁用', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表'; ``` 其中,`status` 字段类型为 `tinyint`,用于存储枚举类型的值。 4. 枚举字段映射 在 MyBatis-Plus 中,我们可以使用 `@EnumValue` 和 `@EnumValue` 注解来进行枚举字段映射。具体使用方法如下: ```java public class User { private Long id; private String name; @EnumValue private StatusEnum status; // getter 和 setter 略 } ``` 在 `status` 字段上添加 `@EnumValue` 注解,表示该字段是枚举类型的值。 ```java public interface UserMapper extends BaseMapper<User> { } ``` 在 Mapper 中继承 `BaseMapper` 接口即可,无需做任何其他配置。 5. 查询操作 在查询操作时,MyBatis-Plus 会自动将数据库中存储的枚举类型的值映射为实体类中的枚举类型。例如: ```java User user = userMapper.selectById(1L); System.out.println(user.getStatus()); // 输出:ENABLE ``` 在上述代码中,MyBatis-Plus 会自动将数据库中的 `status` 字段的值 `1` 映射为实体类中的 `StatusEnum.ENABLE`。 6. 插入和更新操作 在插入和更新操作时,MyBatis-Plus 会自动将实体类中的枚举类型映射为数据库中的枚举类型的值。例如: ```java User user = new User(); user.setName("张三"); user.setStatus(StatusEnum.ENABLE); userMapper.insert(user); ``` 在上述代码中,MyBatis-Plus 会自动将实体类中的 `StatusEnum.ENABLE` 映射为数据库中的 `status` 字段的值 `1`。 综上所述,使用 MyBatis-Plus 枚举字段映射非常方便,只需要在实体类中添加 `@EnumValue` 注解即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值