连连看游戏

连连看游戏_第1张图片连连看游戏_第2张图片连连看游戏_第3张图片

连通块+记忆性递归的综合运用

这里x,y的设置反我平常的习惯,搞得我有点晕

实际上可以一输入就交换x,y的数据的

如果设置y1为全局变量的话会warning:

warning: built-in function 'y1' declared as non-function

所以我改成p和q了

刚开始判断能不能相连是靠连通块

后面求最短线段数是靠记忆性递归

代码如下:

#include
struct Min{
    int x_d;//x轴的方向
    int y_d;//y轴的方向
    int len;
}min[77][77];
void fill(int color, int x, int y);
bool judge(int m1, int n1, int m2, int n2);
void dg(int y, int x, int color, int y_d, int x_d);
int map[77][77];
int w, h, p1, q1, p2, q2;

int main(void)
{
    //板子输入
    scanf("%d%d", &w, &h);
    getchar();
    for(int i = 1; i <= h; i++)
    {
        char c;
        for(int j = 1; j <= w; j++)
            if((c = getchar()) == 'X')
                map[i][j] = 1;
            else
                map[i][j] = 0;
        getchar();
    }
    //开始填充连通块
    int color = 2;
    fill(color++, 0, 0);
    for(int i = 1; i <= h; i++)
        for(int j = 1; j <= w; j++)
            if(map[i][j] == 0)
                fill(color++, i, j);
    //开始判断并计算
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d%d%d", &p1, &q1, &p2, &q2);
        if(judge(p1, q1, p2, q2))
        {
            printf("impossible\n");
            continue;
        }
        //重置min数组
        for(int i = 0; i <= h + 1; i++)
            for(int j = 0; j <= w + 1; j++)
                min[i][j].len = 100, min[i][j].x_d = 0, min[i][j].y_d = 0;
        min[q1][p1].len = 0;
        //求最短线段数(从x1,y1到x2,y2)
        if(map[q1 + 1][p1] != 1) dg(q1 + 1, p1, map[q1 + 1][p1], 1, 0);
        if(map[q1 - 1][p1] != 1) dg(q1 - 1, p1, map[q1 - 1][p1], -1, 0);
        if(map[q1][p1 + 1] != 1) dg(q1, p1 + 1, map[q1][p1 + 1], 0, 1);
        if(map[q1][p1 - 1] != 1) dg(q1, p1 - 1, map[q1][p1 - 1], 0, -1);
        //得到最短线段数
        int minn = 100;
        if(map[q2 + 1][p2] != 1)
        {
            int tmp = min[q2 + 1][p2].len + ((min[q2 + 1][p2].x_d == 0 && min[q2 + 1][p2].y_d == -1) ? 0 : 1);
            minn = (minn < tmp) ? minn : tmp;
        }
        if(map[q2 - 1][p2] != 1)
        {
            int tmp = min[q2 - 1][p2].len + ((min[q2 - 1][p2].x_d == 0 && min[q2 - 1][p2].y_d == 1) ? 0 : 1);
            minn = (minn < tmp) ? minn : tmp;
        }
        if(map[q2][p2 + 1] != 1)
        {
            int tmp = min[q2][p2 + 1].len + ((min[q2][p2 + 1].x_d == -1 && min[q2][p2 + 1].y_d == 0) ? 0 : 1);
            minn = (minn < tmp) ? minn : tmp;
        }
        if(map[q2][p2 - 1] != 1)
        {
            int tmp = min[q2][p2 - 1].len + ((min[q2][p2 - 1].x_d == 1 && min[q2][p2 - 1].y_d == 0) ? 0 : 1);
            minn = (minn < tmp) ? minn : tmp;
        }
        //输出
        if(minn > 10)  printf("impossible\n");
        else  printf("%d\n", minn);
    }
    
    return 0;
}
void fill(int color, int x, int y)
{
    if(map[x][y])  return;
    if(x < 0 || y < 0 || x > h + 1 || y > w + 1)  return;

    map[x][y] = color;
    fill(color, x + 1, y), fill(color, x - 1, y);
    fill(color, x, y + 1), fill(color, x, y - 1);
    return;
}
bool judge(int m1, int n1, int m2, int n2)
{
    int tmp1[4] = {map[n1 + 1][m1], map[n1 - 1][m1], map[n1][m1 + 1], map[n1][m1 - 1]};
    int tmp2[4] = {map[n2 + 1][m2], map[n2 - 1][m2], map[n2][m2 + 1], map[n2][m2 - 1]};
    for(int i = 0; i < 4; i++)
    {
        if(tmp1[i] == 1)  continue;
        for(int j = 0; j < 4; j++)
        {
            if(tmp2[j] == 1)  continue;
            if(tmp1[i] == tmp2[j])  return false;
        }
    }
    return true;//只是代表是否执行if,而不是能不能连通
}
void dg(int y, int x, int color, int y_d, int x_d)
{
    if(x < 0 || y < 0 || x > w + 1 || y > h + 1)  return;
    if(map[y][x] != color)  return;
    int tmp = min[y - y_d][x - x_d].len + ((x_d == min[y - y_d][x - x_d].x_d && y_d == min[y - y_d][x - x_d].y_d) ? 0 : 1);
    if(tmp > min[y][x].len)  return;//等于的话不用返回

    min[y][x].len = tmp, min[y][x].x_d = x_d, min[y][x].y_d = y_d;
    dg(y + 1, x, color, 1, 0);
    dg(y - 1, x, color, -1, 0);
    dg(y, x + 1, color, 0, 1);
    dg(y, x - 1, color, 0, -1);
    return;
}

这里实际上可以改一下目的地的color(本来是1),使旁边的块可以直接走到目的地,而不是目的地旁边

只要在4个方向的递归开始的时候改成相应的颜色就可以了,记得改回来,以后还要用

这样就不会显得累赘,可以把求最短线段数部分和得到最短线段数部分合并,代码会更短一点

懒得改了

你可能感兴趣的:(c语言,算法)