zoukankan      html  css  js  c++  java
  • UVA 519 Puzzle (II)

    UVA_519

        一开始裸的回溯,超时,后来想到了一些预判断,但还是超时了,看了UVA论坛上一个人发帖说预判断也没能saving他,于是我险些放弃了继续仔细想预判断的想法。

        后来去W.C.的时候想到了更细化的预判断,出来之后又按这个思路继续想,于是得到了更多更细化的预判断,最终AC了,感觉细致的预判断是很强的剪枝呀。

        我在预判断的时候主要考虑了下面几点:

        ①从全局角度讲,IO个数应该相等。

        ②所有的F的个数应是2*(M+N),但这样还不够细致,我们仔细想一下不难得到下面这个更细致的条件,top和bottom中F的个数分别为M,left和right中F的个数分别为N。

        ③受讨论②时把四条边分开来看的启发,我们也可以想到上、下两个边缘上left和right的总IO个数应该相等,同理,左、右两个边缘上top和bottom的总IO个数也应该相等。

        ④根据拼图的规格,角上的F的个数应该是有限制的,不妨把这个限制的数量叫做limitk。比如如果N和M都为1,那么角应该有4个F,如果N和M有且仅有一个为1,那么角应该有3个F,如果N和M都不为1,那么角应该有2个F。上面的分析给了我们两点启发,第一,角上的F是最多的,因此若有一个拼图块的F的个数超过了limitk,显然无解,第二,如果满足F数为limitk的角的数量不符合相应的值的话,自然也无解。我的程序中并没有细化到每个角,只是看每个拼图块是否有limitk个F,实际上还可以根据F的位置再一步细化出是否各个角都有且仅有一个。

    #include<stdio.h>
    #include<string.h>
    #define MAXD 40
    #define MAXN 10
    int N, M, T, top[MAXD], right[MAXD], bottom[MAXD], left[MAXD];
    int D[MAXN][MAXN], R[MAXN][MAXN], A[MAXD];
    char b[MAXN], *str = "IFO";
    void init()
    {
    int i, j, k;
    T = N * M;
    for(i = 0; i < T; i ++)
    {
    scanf("%s", b);
    top[i] = strchr(str, b[0]) - str - 1;
    right[i] = strchr(str, b[1]) - str - 1;
    bottom[i] = strchr(str, b[2]) - str - 1;
    left[i] = strchr(str, b[3]) - str - 1;
    }
    }
    int place(int cur, int x, int y)
    {
    if(x == 0 && top[cur] != 0)
    return 0;
    if(x != 0 && top[cur] + D[x - 1][y] != 0)
    return 0;
    if(y == M - 1 && right[cur] != 0)
    return 0;
    if(y != M - 1 && right[cur] == 0)
    return 0;
    if(x == N - 1 && bottom[cur] != 0)
    return 0;
    if(x != N - 1 && bottom[cur] == 0)
    return 0;
    if(y == 0 && left[cur] != 0)
    return 0;
    if(y != 0 && left[cur] + R[x][y - 1] != 0)
    return 0;
    return 1;
    }
    int dfs(int x, int y)
    {
    int i, j, k;
    if(y == M)
    ++ x, y = 0;
    if(x == N)
    return 1;
    for(i = 0; i < T; i ++)
    if(!A[i] && place(i, x, y))
    {
    A[i] = 1;
    D[x][y] = bottom[i], R[x][y] = right[i];
    if(dfs(x, y + 1))
    return 1;
    A[i] = 0;
    }
    return 0;
    }
    int check()
    {
    int i, j, k, limitk, upcnt, downcnt, leftcnt, rightcnt;
    int iototal, ioup, iodown, ioleft, ioright, num;
    iototal = ioup = iodown = ioleft = ioright = 0;
    upcnt = downcnt = leftcnt = rightcnt = num = 0;
    if(N == 1 && M == 1)
    limitk = 4;
    else if(N == 1 || M == 1)
    limitk = 3;
    else
    limitk = 2;
    for(i = 0; i < T; i ++)
    {
    k = 0;
    if(top[i] == 0)
    ++ upcnt, ++ k, ioup = ioup + (left[i] + right[i]);
    if(right[i] == 0)
    ++ rightcnt, ++ k, ioright = ioright + (top[i] + bottom[i]);
    if(bottom[i] == 0)
    ++ downcnt, ++ k, iodown = iodown + (left[i] + right[i]);
    if(left[i] == 0)
    ++ leftcnt, ++ k, ioleft = ioleft + (top[i] + bottom[i]);
    if(k > limitk)
    return 0;
    if(k == limitk)
    ++ num;
    iototal = iototal + (top[i] + right[i] + bottom[i] + left[i]);
    }
    if(limitk == 2 && num != 4)
    return 0;
    if(limitk == 3 && num != 2)
    return 0;
    if(limitk == 4 && num != 1)
    return 0;
    if(upcnt != M || downcnt != M || leftcnt != N || rightcnt != N)
    return 0;
    if(iototal != 0 || ioup != 0 || ioright != 0 || iodown != 0 || ioleft != 0)
    return 0;
    return 1;
    }
    void solve()
    {
    if(!check())
    {
    printf("NO\n");
    return ;
    }
    memset(A, 0, sizeof(A));
    if(dfs(0, 0))
    printf("YES\n");
    else
    printf("NO\n");
    }
    int main()
    {
    for(;;)
    {
    scanf("%d%d", &N, &M);
    if(!N && !M)
    break;
    init();
    solve();
    }
    return 0;
    }


  • 相关阅读:
    mysql pt-osc
    mysql表分区,mysql分区表
    mysql5.5无法启动,Can't open and lock privilege tables: Table 'mysql.host' doesn't exist 问题的解决方法
    mysql压缩表,mysql行压缩与页压缩
    mybase7破解
    (1.5)es集群部署运维【最佳实践】
    kafka基础概念
    midway日志体系
    midwayjs 使用egg-mysql
    midway mysql egg-mysql 配置 基础操作 增删改查
  • 原文地址:https://www.cnblogs.com/staginner/p/2299706.html
Copyright © 2011-2022 走看看