2010-1158
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
== 题目大意 ==
40000 * 40000 的格子,```(x, y) | (x == 0 || y == 0)``` 是河流。
一个具有人猪二象性的东西从 ```(x, y)``` 开始跳跃,每次跳跃可以到 ```(x - k * y, y)``` 或者 ```(x, y - k * x)``` 。
作为人的时候,他可以做出选择,作为猪的时候,它会随机跳跃。跳过之后会从人变成猪或者从猪变成人,但是如果跳到河里面就不能变了。
这个东西从 ```(x, y)``` 开始跳跃,可以从人和猪里面选择一个身份。
如果这个东西想要最终变成人,问应该选择什么?
== 分析 ==
博弈类题目,很容易确定边界条件(河流),然后按照人或者猪的思考方式,考虑每个格子即可。由于没有后效性,可以使用之前已经确定的格子的结果计算后面的格子。
== 参考程序 ==
{{{
#!cpp
#include <stdio.h>
#include <cstring>
#define N 60000
char a[N];
int x,y;
char& geta(int x0, int y0) {
return a[x0*y+y0];
}
void calc(int px, int py) {
// if can jump into river, must use pig
// printf("calc %d %d\n", px, py);
/*if (px % py == 0 || py % px == 0) {
geta(px,py) = 'P';
return;
}*/
// jump left
int jh = 0, jp = 0;
for (int k = 1; k < N; k++) {
// x - k * y, y
int xt = (px - k * py);
if (xt > 0) {
jh += (geta(xt,py) == 'H');
jp += (geta(xt,py) == 'P');
if (jp) goto ret;
} else break;
}
// jump top
for (int k = 1; k < N; k++) {
// x - k * y, y
int yt = (py - k * px);
if (yt > 0) {
jh += (geta(px,yt) == 'H');
jp += (geta(px,yt) == 'P');
if (jp) goto ret;
} else break;
}
// printf("calc %d %d\n", px, py);
// if can only jump to H, use pig
ret:
if (jp == 0) {
geta(px,py) = 'P';
return;
} else {
geta(px,py) = 'H';
return;
}
}
int main(int argc, char const* argv[])
{
int nc = 0;
while(scanf("%d%d", &x, &y) == 2) {
memset(a, '@', sizeof(a));
geta(1,1) = 'P';
for (int i = 2; i <= x; i++) {
geta(i,1) = 'H';
}
for (int i = 2; i <= y; i++) {
geta(1,i) = 'H';
}
for (int yi = 2; yi <= y; yi++) {
for (int xi = 2; xi <= x; xi++) {
calc(xi,yi);
}
}
printf("Case #%d:\n", ++nc);
for (int xi = 1; xi <= x; xi++) {
for (int yi = 1; yi <= y; yi++) {
printf("%c", geta(xi,yi));
}
puts("");
}
}
return 0;
}
}}}
题目大意
40000 * 40000 的格子,``(x, y) | (x == 0 || y == 0)`` 是河流。
一个具有人猪二象性的东西从 ``(x, y)` 开始跳跃,每次跳跃可以到 `(x - k * y, y)` 或者 `(x, y - k * x)`` 。
作为人的时候,他可以做出选择,作为猪的时候,它会随机跳跃。跳过之后会从人变成猪或者从猪变成人,但是如果跳到河里面就不能变了。
这个东西从 ``(x, y)`` 开始跳跃,可以从人和猪里面选择一个身份。
如果这个东西想要最终变成人,问应该选择什么?
分析
博弈类题目,很容易确定边界条件(河流),然后按照人或者猪的思考方式,考虑每个格子即可。由于没有后效性,可以使用之前已经确定的格子的结果计算后面的格子。
参考程序
#include <stdio.h>
#include <cstring>
#define N 60000
char a[N];
int x,y;
char& geta(int x0, int y0) {
return a[x0*y+y0];
}
void calc(int px, int py) {
// if can jump into river, must use pig
// printf("calc %d %d\n", px, py);
/*if (px % py == 0 || py % px == 0) {
geta(px,py) = 'P';
return;
}*/
// jump left
int jh = 0, jp = 0;
for (int k = 1; k < N; k++) {
// x - k * y, y
int xt = (px - k * py);
if (xt > 0) {
jh += (geta(xt,py) == 'H');
jp += (geta(xt,py) == 'P');
if (jp) goto ret;
} else break;
}
// jump top
for (int k = 1; k < N; k++) {
// x - k * y, y
int yt = (py - k * px);
if (yt > 0) {
jh += (geta(px,yt) == 'H');
jp += (geta(px,yt) == 'P');
if (jp) goto ret;
} else break;
}
// printf("calc %d %d\n", px, py);
// if can only jump to H, use pig
ret:
if (jp == 0) {
geta(px,py) = 'P';
return;
} else {
geta(px,py) = 'H';
return;
}
}
int main(int argc, char const* argv[])
{
int nc = 0;
while(scanf("%d%d", &x, &y) == 2) {
memset(a, '@', sizeof(a));
geta(1,1) = 'P';
for (int i = 2; i <= x; i++) {
geta(i,1) = 'H';
}
for (int i = 2; i <= y; i++) {
geta(1,i) = 'H';
}
for (int yi = 2; yi <= y; yi++) {
for (int xi = 2; xi <= x; xi++) {
calc(xi,yi);
}
}
printf("Case #%d:\n", ++nc);
for (int xi = 1; xi <= x; xi++) {
for (int yi = 1; yi <= y; yi++) {
printf("%c", geta(xi,yi));
}
puts("");
}
}
return 0;
}