UVa 639 - Don't Get Rooked

来源:互联网 发布:自学编程的视频网站 编辑:程序博客网 时间:2024/06/08 14:18

类似“八皇后问题”,但加了“墙”的概念,如果有墙相隔,则同一行墙两边可同时存在两个元素。

枚举子集+判断可行性,在枚举子集时,可以进行适当剪枝,如此可以减少很多不必要的枚举,比如:当n == 4时,其最大的的“车”的位置为8个,则我们可以加一个计数器,最多将子集的枚举量设为8,超过8则不再往子集中加入元素。

代码如下:

#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>using namespace std;int n, num, num_1, cct;int flag[20],save[5] = {0, 2, 3, 6, 9}; // n为1,2,3,4时对应的最大可行的“位置”个数char a[5][5], c[5][5];struct point{    int x, y;} po[20];int judge() // 判断子集是否可行{    memcpy(c, a, sizeof(a));    for(int i = 0; i < num; i++)        if(flag[i])            c[po[i].x][po[i].y] = '*';    for(int i = 0; i < n; i++)        for(int j = 0; j < n; j++)            if(c[i][j] == '*')            {                for(int ii = i + 1, fl = 1; ii < n; ii++)                {                    if(c[ii][j] == 'X')                        fl = 0;                    else if(c[ii][j] == '*' && fl)                        return 0;                }                for(int jj = j + 1, fl = 1; jj < n; jj++)                {                    if(c[i][jj] == 'X')                        fl = 0;                    else if(c[i][jj] == '*' && fl)                        return 0;                }            }    return 1;}int subset(int cur) // 对所有‘.’的位置进行枚举{    if(cur == num)    {        int fl = judge();        if(fl && num_1 > cct)            cct = num_1;        return fl;    }    flag[cur] = 1;    ++num_1;    if(num_1 < save[n])        subset(cur + 1);    --num_1;    flag[cur] = 0;    subset(cur + 1);    return 0;}int main(){#ifdef test    freopen("sample.txt", "r", stdin);#endif    while(scanf("%d", &n), n)    {        cct = num_1 = num = 0;        for(int i = 0; i < n; i++)            scanf("%s", a[i]);        for(int i = 0; i < n; i++)            for(int j = 0; j < n; j++)                if(a[i][j] == '.')                {                    po[num].x = i;                    po[num++].y = j;                }        subset(0);        printf("%d\n", cct);    }    return 0;}


原创粉丝点击