uva 10318 Security Panel (dfs+剪枝)

uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1259

  压缩Panel的全部状态,预处理出每个位置的变化,然后dfs搜索全部情况。不过这样是会超时的,所以我在搜索的过程中加上剪枝,预判出之前的状态是否能够使得最后整个Panel充满,如果不能就尽早跳出搜索。加上小小的一个剪枝,速度提升估计了不下1000倍,由原来的超时,最后只要0.008s就完成了!

代码如下:

View Code
 1 #define REP(i, n) for (int i = 0; i < (n); i++)
 2 #define REP_1(i, n) for (int i = 1; i <= (n); i++)
 3 
 4 const int dir[9][2] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 0}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
 5 char buf[3][4];
 6 LL pat[25], ok[6];
 7 
 8 void pntPat(LL n) {
 9     printf("~~~~~ %lld ~~~~~~\n", n);
10     DEC(i, 63, 0) {
11         if (n & (1ll << i)) putchar('1');
12         else putchar('0');
13         if ((i & 7) == 0) puts("");
14     }
15 }
16 
17 void makePat(int n, int m) {
18     int t = (1 << m) - 1 << 1;
19     REP(i, n + 1) {
20         ok[i] = 0;
21         REP(j, i) {
22             ok[i] |= t;
23             ok[i] <<= 8;
24         }
25 //        pntPat(ok[i]);
26     }
27     REP(i, n) {
28         REP(j, m) {
29             int id = i * m + j;
30             pat[id] = 0;
31             REP(k, 9) {
32                 int x = dir[k][0] + i + 1, y = dir[k][1] + j + 1;
33                 if (buf[k / 3][k % 3] == '*') pat[id] |= 1ll << x * 8 + y;
34             }
35 //            cout << id << endl;
36 //            pntPat(pat[id]);
37         }
38     }
39 }
40 
41 int rec[30], cnt;
42 
43 bool dfs(LL cur, int pos, int end, int n, int m) {
44     if ((cur & ok[n]) == ok[n]) return true;
45     if (pos >= end) return false;
46     int t = pos / m - 1;
47 //    cout << pos << ends << m << ends << t << endl;
48     if (t > 0 && (cur & ok[t]) != ok[t]) return false;
49     if (dfs(cur, pos + 1, end, n, m)) return true;
50     rec[cnt++] = pos + 1;
51     if (dfs(cur ^ pat[pos], pos + 1, end, n, m)) return true;
52     cnt--;
53     return false;
54 }
55 
56 void work(int n, int m) {
57     makePat(n, m);
58     cnt = 0;
59     if (dfs(0, 0, n * m, n, m)) {
60         REP(i, cnt) {
61             if (i) putchar(' ');
62             printf("%d", rec[i]);
63         }
64         puts("");
65     } else {
66         puts("Impossible.");
67     }
68 }
69 
70 int main() {
71 //    freopen("in", "r", stdin);
72     int n, m, cas = 1;
73     while (~scanf("%d%d", &n, &m) && (n || m)) {
74         REP(i, 3) scanf("%s", buf[i]);
75         printf("Case #%d\n", cas++);
76         work(n, m);
77     }
78     return 0;
79 }

 

——written by Lyon

 

转载于:https://www.cnblogs.com/LyonLys/archive/2013/02/26/uva_10318_Lyon.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值