夹吃棋
题目描述
在一个 3 * 3 的棋盘上,小红和小紫正在玩“夹吃棋”。 所谓“夹吃棋”,即如果存在一个白子,它的两侧 (横向或者纵向)相邻都是黑子,则这个棋子将被“夹吃”,对于黑棋亦然。
如果一个棋盘的局面没有一方被夹吃,或者黑白双方都被对面夹吃,则认为是平局。如果只有一方夹吃了另一方,则认为夹吃方赢,被夹吃方输。
小红执黑棋,小紫执白棋,现在给定一个局面,请你判断当前棋局是谁获胜。
输入描述:
第一行输入一个正整数 t (1 <= t <= 10000),代表询问的次数。
接下来每组询问输入三行,,每行是一个长度为3的字符串,字符串仅由’o’,‘.’,'*'组成。
其中 o 代表白棋,* 代表黑棋,. 代表未放置棋子。
输出描述:
小红获胜输出“kou”,小紫获胜输出“yukan”,平局输出“draw”。
输入示例:
3
...
o*o
...
o**
ooo
..*
o*o
*o*
o*o
输出示例:
yukan
kou
draw
思路
为了方便判断,我将字符转换成了int。
#include <bits/stdc++.h>
using namespace std;
int t; // 询问次数
int m[3][3]; // 0-未放置;1-'*';-1-'o'
int main(){
string s;
cin >> t;
while(t--){
for(int i = 0; i < 3; i++){
s.clear();
cin >> s;
for(int j = 0; j < 3; j++){
if(s[j] == '.') m[i][j] = 0;
else if(s[j] == '*') m[i][j] = 1;
else if(s[j] == 'o') m[i][j] = -1;
}
}
int flag_kou = 0;
int flag_yukan = 0;
for(int i = 0; i < 3; i++){
if(m[i][1] != 0 && (m[i][1] + m[i][0]) == 0 && (m[i][1] + m[i][2]) == 0){
if(m[i][1] == 1) flag_yukan = 1;
else if(m[i][1] == -1) flag_kou = 1;
}
if(m[1][i] != 0 && (m[1][i] + m[0][i]) == 0 && (m[1][i] + m[2][i]) == 0){
if(m[1][i] == 1) flag_yukan = 1;
else if(m[1][i] == -1) flag_kou = 1;
}
}
if(flag_kou == 1 && flag_yukan == 0) cout << "kou" << endl;
else if(flag_kou == 0 && flag_yukan == 1) cout << "yukan" << endl;
else cout << "draw" << endl;
}
return 0;
}
小红买药
题目描述
小红准备买药治病。已知共有 n 种症状和 m 种药,第 i 种药可以治疗一些症状,但可能会导致一些副作用,添加一些新的症状。小红依次服用了一些药,请你告诉小红,当她每次服用一副药时,当前还有多少症状?
输入描述:
- 第一行输入一个正整数
n
(1 <= n <= 20),代表症状的数量 - 第二行输入一个长应为 n 的 01 串,第 i 位是 “1” 代表小红目前有第 i 个症状,第i位是 “0” 代表没有该症状。
- 第三行输入一个正整数
m
( 1<= m <= 10^4),代表药的数量。 - 接下来的 2 * m 行,每 2 行描述一副药:
- 第一行输入一个长度为 n 的 01 串,代表该药能治疗的症状。’1‘代表可以治疗,‘0’代表不能治疗。
- 第二行输入一个长度为 n 的 01 串,代表该药会产生的副作用。’1‘代表会产生该症状,’0‘代表不会产生。
- 接下来的一行,输入一个正整数
q
( 1<= q <= 10^4),代表小红服用的药数量。 - 接下来的
q
行,每行输入一个正整数u
(1 <= ai, u <= m),代表小红服用了第 u 副药。
保证每副药的副作用产生的症状和该药治疗的症状是不会重复的,即不会存在同一个位置的两个 01 串都是‘1’。
输出描述:
输出 q 行,每行输入一个正整数,代表当前小红服用药后,身体有多少症状。
输入示例:
4
0101
3
1100
0010
0101
1000
1001
0000
3
2
3
1
输出示例:
1
0
1
思路
注意接收数据的时候会遗漏“0”
#include <bits/stdc++.h>
using namespace std;
#define N 20
#define M 10004
int n; // 症状的数量
int zz[N]; // 当前症状情况
int m; // 药的数量
int zl[M][N]; // 治疗功能
int fzy[M][N]; // 副作用
int q; // 服用药的数量
int idx; // 当前服用药的index
int main(){
cin >> n;
char c;
for(int i = 0; i < n; i++){
cin >> c;
if(c=='0')zz[i] = 0;
else zz[i] = 1;
}
cin >> m;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
cin >> c;
if(c == '0') zl[i][j] = 0;
else zl[i][j] = 1;
}
for(int j = 0; j < n; j++){
cin >> c;
if(c == '0') fzy[i][j] = 0;
else fzy[i][j] = 1;
}
}
cin >> q;
while(q--){
cin >> idx;
idx--;
int count = 0;
for(int i = 0; i < n; i++){
if(zl[idx][i] == 1) zz[i] = 0; // 如果这副药能治愈第i种症状,无论有没有症状,吃下一定是无症状
// 考虑副作用
if(fzy[idx][i] == 1) zz[i] = 1;
if(zz[i] == 1) count++;
}
cout << count << endl;
}
return 0;
}
皇后移动的最小步数
题目描述
有一个 n 行 m 列的棋盘,有一些格子是障碍物不能通过。
小红控制一个皇后在从左上角出发,每次移动她可以控制皇后进行以下三种方式中的一种:
-
向右移动若干个格子。
-
向下移动若干个格子。
-
向右下移动若干个格子。
用数学语言描述,当前的坐标在 (x, y) 时,每次移动可以到 (x + k, y) 或 (x, y + k) 或 (x + k, y + k) 其中 k 为任意正整数。移动的前提是,路径上没有障碍物。 小红想知道,皇后从左上角移动到右下角,最少要移动多少步?
输入描述:
第一行输入两个正整数 n 和 m(1 <= n,m <= 2000),代表行数和列数。
接下来的 n 行,每行输入一个长度 m 的字符串,用来表示棋盘。
其中 “.” 代表可以通过的位置,“*” 代表障碍物。 保证左上角和右下角都不是障碍物。
输出描述:
如果无法到达,请输出-1。
否则输出一个整数,代表最少的移动次数。
输入示例:
4 5
...*.
*..**
.....
.....
输出示例:
2
思路
BFS
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct State {
int x, y, steps;
};
int main() {
int n, m;
cin >> n >> m;
vector<string> board(n);
for (int i = 0; i < n; ++i) {
cin >> board[i];
}
if (board[0][0] == '*' || board[n-1][m-1] == '*') {
cout << -1 << endl;
return 0;
}
vector<vector<bool>> visited(n, vector<bool>(m, false));
queue<State> q;
q.push({0, 0, 0});
visited[0][0] = true;
while (!q.empty()) {
State curr = q.front();
q.pop();
if (curr.x == n - 1 && curr.y == m - 1) {
cout << curr.steps << endl;
return 0;
}
// Three possible directions
// Right
for (int k = 1; curr.y + k < m; ++k) {
if (board[curr.x][curr.y + k] == '*') break;
if (!visited[curr.x][curr.y + k]) {
visited[curr.x][curr.y + k] = true;
q.push({curr.x, curr.y + k, curr.steps + 1});
}
}
// Down
for (int k = 1; curr.x + k < n; ++k) {
if (board[curr.x + k][curr.y] == '*') break;
if (!visited[curr.x + k][curr.y]) {
visited[curr.x + k][curr.y] = true;
q.push({curr.x + k, curr.y, curr.steps + 1});
}
}
// Diagonal
for (int k = 1; curr.x + k < n && curr.y + k < m; ++k) {
if (board[curr.x + k][curr.y + k] == '*') break;
if (!visited[curr.x + k][curr.y + k]) {
visited[curr.x + k][curr.y + k] = true;
q.push({curr.x + k, curr.y + k, curr.steps + 1});
}
}
}
cout << -1 << endl;
return 0;
}
DP(超时)
#include <iostream>
#include <vector>
using namespace std;
const int INF = 4e6;
int n, m; // 行数。列数
int main(){
cin >> n >> m;
vector<vector<char>> grid(n, vector<char>(m));
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin >> grid[i][j];
}
}
vector<vector<int>> dp(n, vector<int>(m, INF));
dp[0][0] = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(grid[i][j] == '*') continue;
// 分三种情况:
// 向下移动
for(int k = i+1; k < n; k++){
dp[k][j] = min(dp[k][j], dp[i][j]+1);
}
// 向右移动
for(int k = j+1; k < m; k++){
dp[i][k] = min(dp[i][k], dp[i][j]+1);
}
// 向右下移动
for(int k = 1; i+ k < n && j + k < m; k++){
dp[i+k][j+k] = min(dp[i+k][j+k], dp[i][j]+1);
}
}
}
if(dp[n-1][m-1] == INF) cout << -1 << endl;
else cout << dp[n-1][m-1] << endl;
}