题目链接
由于锁的齿轮的数量比较少,所以可以对每个齿轮,尝试向上拨或向下拨两种方法来更新最小转动次数。具体可以用模10下的加减法来实现。
#include <bits/stdc++.h>
using namespace std;
int n, a, b, ans;
string s, t;
int main() {
scanf("%d", &n);
cin >> s >> t;
ans = 0;
for(int i = 0; i < n; i++) {
a = (s[i] - t[i] + 10) % 10;
b = (t[i] - s[i] + 10) % 10;
ans += min(a, b);
}
printf("%d\n", ans);
return 0;
}
可以从题目中抽取出主角分数的三个限制条件:
于是可以想到的一种可行的策略是:当考低分段(小于中位数)的分数的次数比较多的时候考 y 分,当考高分段(大于或等于中位数)的分数的次数比较多的时候考 1 分。这样就能够在满足前两种情况的前提下,拿到可能拿到的最低分。此时若能够满足第三种条件,那么就构造出了一种可行解。若不能满足第三种条件的话无论如何都不能构造出可行解了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3;
int n, p, k, x, y, low, high, mark, sum, ans[maxn];
int main() {
cin >> n >> k >> p >> x >> y;
low = high = sum = 0;
for(int i = 0; i < k; i++) {
cin >> mark;
sum += mark;
if(mark < y) low++;
else high++;
}
for(int i = 0; i < n - k; i++) {
if(low >= high) {
ans[i] = y;
sum += y;
high++;
}
else {
ans[i] = 1;
sum++;
low++;
}
}
if(low < high && sum <= x) {
for(int i = 0; i < n - k; i++) {
printf("%d ", ans[i]);
}
puts("");
}
else puts("-1");
return 0;
}
典型的路径寻找问题。用搜索来解决。注意如果用DFS来解决的话不用保护现场,因为被破坏的现场有“记忆”功能,能够减少很多枚举量。若保护现场则复杂度变成指数级别,提交会超时。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
char G[maxn][maxn];
int n, m, r1, c1, r2, c2;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
bool dfs(int x, int y) {
if(G[x][y] != '.') {
return x == r2 && y == c2;
}
G[x][y] = 'X';
for(int i = 0; i < 4; i++) {
if(dfs(x + dx[i], y + dy[i])) {
return true;
}
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%s", G[i] + 1);
}
scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
G[r1][c1] = '.';
puts(dfs(r1, c1) ? "YES" : "NO");
return 0;
}
#include <bits/stdc++.h>
using namespace std;
struct p {
int x, y;
p(int x, int y): x(x), y(y) {}
};
const int maxn = 505;
char G[maxn][maxn];
int n, m, x, y, a, b, r1, c1, r2, c2;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
queue <p> q;
bool bfs() {
q.push(p(r1, c1));
while(!q.empty()) {
p node = q.front();
q.pop();
x = node.x, y = node.y;
if(G[x][y] == 'X' && x == r2 && y == c2) {
return true;
}
if(G[x][y] == 'X') continue;
G[x][y] = 'X';
for(int i = 0; i < 4; i++) {
a = x + dx[i], b = y + dy[i];
if(G[a][b] == '.' || a == r2 && b == c2) {
q.push(p(a, b));
}
}
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%s", G[i] + 1);
}
scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
G[r1][c1] = '.';
puts(bfs() ? "YES" : "NO");
return 0;
}
不好直接求解的概率问题通常都是用动态规划去做。本题的状态可以这样设计: (i,j,k) 表示目前岛上居住着的石头,剪刀和布的个数分别为 i,j,k 。如果我们用 d[i][j][k] 来表示状态 (i,j,k) 发生的概率的话,最终我们的答案就是求 ∑d[0][0][k],∑d[0][j][0]和∑d[i][0][0] 。初始状态(r, s, p)的概率为1。现尝试找状态转移方程。对于状态 (i,j,k) ,可以转移到这个状态的状态为 (i+1,j,k),(i,j+1,k)和(i,j,k+1) 。发生转移的情况分别为石头与布相遇(石头减少),石头与剪刀相遇(剪刀减少)和剪刀与布相遇(布减少)。于是就有转移方程: d[i][j][k]= 石头与布相遇的概率 ×d[i+1][j][k]+ 石头与剪刀相遇的概率 ×d[i][j+1][k]+ 石头与布相遇的概率 ×d[i][j][k+1] 。事实上只剩下两种生物的状态还要向只剩下一种生物的状态转移,转移的概率都为 1 。但是为了降低编程复杂度,我们可以直接把还剩下两种生物的状态当成只剩下一种生物的状态。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
int r, s, p, m;
double sum, a, b, c, d[maxn][maxn][maxn];
int main() {
scanf("%d%d%d", &r, &s, &p);
memset(d, 0, sizeof(d));
d[r][s][p] = 1;
for(int i = r; i > 0; i--) {
for(int j = s; j > 0; j--) {
for(int k = p; k > 0; k--) {
// 总情况的数量
sum = i * j + j * k + k * i;
// 石头和剪刀相遇
d[i][j-1][k] += i * j / sum * d[i][j][k];
// 剪刀和布相遇
d[i][j][k-1] += j * k / sum * d[i][j][k];
// 布和石头相遇
d[i-1][j][k] += i * k / sum * d[i][j][k];
}
}
}
a = b = c = 0;
m = max(max(r, s), p);
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= m; j++) {
// 石头幸存的情况
a += d[i][j][0];
// 剪刀幸存的情况
b += d[0][i][j];
// 布幸存的情况
c += d[i][0][j];
}
}
printf("%.10f %.10f %.10f\n", a, b, c);
return 0;
}