搜索题集锦(无限更新中……)

搜索题集锦(无限更新中……)

把最近遇到的搜索好题列一下(推荐做做)。

http://acm.pku.edu.cn/JudgeOnline/problem?id=2286
The Rotation Game
迭代深搜,中等难度。
一开始用广搜做,结果MLE(当然有可能程序写错),改成迭代深搜后,因为不用考虑判重,不用写状态压缩,程序变的特别简单,再加上一个剪枝后就过了。
剪枝:(8 - 中间8个格最多的数字的个数)> 剩余步数,则剪枝

POJ 2286
 1 //2286_TheRotationGame ~ alpc02
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 24;
 6 const int L = 60;
 7 
 8 int to[8][7= 
 9 {
10     {0,2,6,11,15,20,22},
11     {1,3,8,12,17,21,23},
12     {10,9,8,7,6,5,4},
13     {19,18,17,16,15,14,13},
14     {23,21,17,12,8,3,1},
15     {22,20,15,11,6,2,0},
16     {13,14,15,16,17,18,19},
17     {4,5,6,7,8,9,10},
18 };
19 int center[8= {6,7,8,11,12,15,16,17};
20 
21 int a[N];
22 
23 int centernum;
24 char path[L];
25 int len;
26 
27 int Max(int a, int b) {return a>b?a:b;}
28 int check()
29 {
30     int i, c[4= {0};
31     for(i=0; i<8; i++)
32         c[a[center[i]]]++;
33     return 8 - Max(c[1], Max(c[2], c[3]));
34 }
35 void go(int *b, int *t)
36 {
37     int i, temp;
38     temp = b[t[0]];
39     for(i=0; i<6; i++)
40         b[t[i]] = b[t[i+1]];
41     b[t[6]] = temp;
42 }
43 bool dfs(int k) {
44     int chk = check();
45     if(chk + k > len)
46         return false;
47     if(k == len) {
48         centernum = a[center[0]];
49         return true;
50     }
51     int t, b[N];
52     memcpy(b, a, sizeof(a));
53     for(t=0; t<8; t++) {
54         memcpy (a, b, sizeof(b));
55         go(a, to[t]);
56         if(dfs(k+1)) {
57             path[k] = 'A' + t;
58             return true;
59         }
60     }
61     memcpy(a, b, sizeof(b));
62     return false;
63 }
64 void solve() {
65     len = 0;
66     while(!dfs(0))
67         len++;
68     path[len] = 0;
69 }
70 bool input() {
71     int i;
72     scanf("%d", a+0);
73     if(a[0== 0)
74         return false;
75     for(i=1; i<N; i++)
76         scanf("%d", a+i);
77     return true;
78 }
79 
80 int main()
81 {
82     while(input()) {
83         solve();
84         if(len == 0)
85             printf("No moves needed\n");
86         else
87             printf("%s\n",path);
88         printf("%d\n", centernum);
89     }
90     return 0;
91 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=1184
聪明的打字员
称之为广搜,可这题真的是不那么好做啊。

一开始,广搜,TLE;然后双广,TLE;然后A*,TLE,当然有可能启发函数太次了。
最后请教 oyjpArt,才明白有那么猛的的算法。

大概思路是把所有操作分两类,一类是置换类,就是只是交换数字位置、移动光标位置,二类是加减类,就是对每个数字加1减1。
然后广搜也是分两步,先搜所有的置换,再“搜”所有的加减。
1、先说第二步,“搜”加减,很简单,每个数字相差几就是几步,加起来就是最小步数。
2、第一个搜,要记录置换的当前状态,光标状态,还有光标曾经过的数字的初始位置(用6位2进制存储,记录这个意思就是说只要经过的数字,以后就允许加减,一气呵成)
。。。写不明白
POJ 1184
  1 //1184 聪明的打字员 ~ alpc02
  2 #include <queue>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 const int INF = 123456;
  7 const int N = 46656;
  8 
  9 int v[6];
 10 int pow[6];
 11 int to[6][6];
 12 bool f[N][6][64= {{{0}}};
 13 
 14 int st[6], ed[6], a[6];
 15 
 16 int Min(int a, int b) {    return a<? a:b;}
 17 void go(int s, int pos, int pass, int &ss, int &ppos, int &ppass, int t) {
 18     ss = s;
 19     ppos = pos;
 20     ppass = pass;
 21     switch(t) {
 22     case 0:
 23         if(ppos != 0) {
 24             ppos--;
 25             ppass |= pow[a[ppos]];
 26         }
 27         return;
 28     case 1:
 29         if(ppos != 5) {
 30             ppos++;
 31             ppass |= pow[a[ppos]];
 32         }
 33         return;
 34     case 2:
 35         ppass |= pow[a[0]];
 36         ss += to[0][ppos] * (a[ppos] - a[0]);
 37         return;
 38     case 3:
 39         ppass |= pow[a[5]];
 40         ss += to[5][ppos] * (a[ppos] - a[5]);
 41         return;
 42     }
 43 }
 44 int dis(int *a, int pass) {
 45     int i, ans = 0;
 46     for(i=0; i<6; i++) {
 47         if(st[a[i]] != ed[i]) {
 48             if(pass & pow[a[i]]) {
 49                 ans += abs(st[a[i]] - ed[i]);
 50             }
 51             else {
 52                 return INF;
 53             }
 54         }
 55     }
 56     return ans;
 57 }
 58 
 59 void cal(int *a, int s, int k) {
 60     int i;
 61     for(i=5; i>=0; i--) {
 62         a[i] = s % k;
 63         s /= k;
 64     }
 65 }
 66 struct node {
 67     int s, pos, g, pass; //组合数状态,当前光标,步数,光标路过的点
 68     node() {}
 69     node(int ss, int ppos, int ppass, int gg) : s(ss), pos(ppos), pass(ppass), g(gg) {}
 70 };
 71 
 72 int solve() {
 73     queue <node> myq;
 74     node now;
 75     int s, pos, pass, g;
 76     int ss, ppos, ppass, gg;
 77     int t;
 78     int ans = INF;
 79 
 80     myq.push(node(18650, pow[0], 0));
 81     f[1865][0][1= true;
 82 
 83     while(!myq.empty()) {
 84         now = myq.front();
 85         myq.pop();
 86         g = now.g;
 87         if(g >= ans) {
 88             continue;
 89         }
 90 
 91         s = now.s;
 92         pos = now.pos;
 93         pass = now.pass;
 94 
 95         cal(a, s, 6);
 96 
 97         ans = Min(ans, dis(a, pass) + g);
 98         
 99         gg = g + 1;
100 
101         for(t=0; t<4; t++) {
102             go(s, pos, pass, ss, ppos, ppass, t);
103             if(!f[ss][ppos][ppass]) {
104                 f[ss][ppos][ppass] = true;
105                 myq.push(node(ss, ppos, ppass, gg));
106             }
107         }
108     }
109     return ans;
110 }
111 
112 void init() {
113     int i, j;
114     v[5= pow[5= 1;
115     for(i=4; i>=0; i--) {
116         v[i] = v[i+1* 6;
117         pow[i] = pow[i+1* 2;
118     }
119     for(i=0; i<6; i++) {
120         for(j=0; j<6; j++) {
121             to[i][j] = v[i] - v[j];
122         }
123     }
124 }
125 int main() {
126     init();
127     int stt, edd;
128     scanf("%d %d"&stt, &edd);
129     cal(st, stt, 10);
130     cal(ed, edd, 10);
131     printf("%d\n", solve());
132     return 0;
133 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=1376
Robot
广搜,容易。
后来加一个启发函数进去,是这样定义的:H(n) = 到目标横向距离 / 3 + 到目标纵向距离 / 3 ,除以3是因为一步可以走3个格子,结果比原来的还要慢。

 

POJ 1376
 1 //1376_ Robot ~ alpc02
 2 #include <queue>
 3 using namespace std;
 4 
 5 int n,m;
 6 int bi, bj, bt, ei, ej;
 7 bool mp[55][55];
 8 bool f[55][55][4];
 9 
10 bool input ()
11 {
12     scanf ("%d %d"&m, &n);
13     int i, j, k;
14     memset (mp, truesizeof(mp));
15     if (m == 0 && n == 0)    return false;
16     for (i=1; i<=m; i++)
17         for (j=1; j<=n; j++)
18         {
19             scanf ("%d"&k);
20             if (k == 1)
21                 mp[i][j] = mp[i-1][j] = mp[i][j-1= mp[i-1][j-1= false;
22         }
23     scanf ("%d %d %d %d"&bi, &bj, &ei, &ej);
24     char ts[10];
25     scanf ("%s", ts);
26     if (ts[0== 'n')
27         bt = 0;
28     if (ts[0== 'e')
29         bt = 1;
30     if (ts[0== 's')
31         bt = 2;
32     if (ts[0== 'w')
33         bt = 3;
34     return true;
35 }
36 
37 struct typ
38 {
39     int i,j,t,s;
40     typ (){}
41     typ (int ii, int jj, int tt, int ss):i(ii),j(jj),t(tt),s(ss){}
42 };
43 int ti[] = {-1,0,1,0};
44 int tj[] = {0,1,0,-1};
45 int solve ()
46 {
47     memset (f, falsesizeof(f));
48     queue <typ> myq;
49 
50     myq.push (typ(bi,bj,bt,0));
51     f[bi][bj][bt] = true;
52     typ now;
53 
54     int i,j,ii,jj,t,s,k;
55     while (!myq.empty ())
56     {
57         now = myq.front ();
58         myq.pop ();
59         i = now.i;
60         j = now.j;
61         t = now.t;
62         s = now.s;
63         if (i==ei && j==ej)
64             return s;
65         for (k=1; k<=3; k++)
66         {
67             ii = i+ti[t]*k;
68             jj = j+tj[t]*k;
69             if (!(ii>0 && ii<&& jj>0 && jj<&& mp[ii][jj]))
70                 break;
71             if (!f[ii][jj][t])
72             {
73                 f[ii][jj][t] = true;
74                 myq.push (typ(ii,jj,t,s+1));
75             }
76         }
77         if (!f[i][j][(t+1)%4])
78         {
79             f[i][j][(t+1)%4= true;
80             myq.push (typ(i,j,(t+1)%4,s+1));
81         }
82         if (!f[i][j][(t+3)%4])
83         {
84             f[i][j][(t+3)%4= true;
85             myq.push (typ(i,j,(t+3)%4,s+1));
86         }
87     }
88     return -1;
89 }
90 
91 int main()
92 {
93     while (input ())
94     {
95         printf ("%d\n", solve ());
96     }
97     return 0;
98 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=2449
Remmarguts' Date
求S到T的K短路,数据量N=1000,M=100000,K=1000。较难

1、用优先队列做广搜,当然跟一般广搜不一样,每个点允许k次出列,第k次出列的T点即是解。(理论上可行,但是实际确MLE超内存)
2、加入启发式函数H——到T的最短距离,传说中的A*就是这样来的。显然 这个最短距离 < i 短距离,满足条件,重要的是事实证明效果很不错。
参考: http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1144
POJ 2449
  1 //2449_kShortestRoute ~ alpc02
  2 #include <queue>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 #define Min(a,b) (a) < (b) ? (a) : (b)
  7 #define INF 12345678
  8 
  9 const int N = 1010;
 10 const int M = 100010;
 11 
 12 int n,m,s,t,k;
 13 int head[N];
 14 int other[M], next[M], len[M];
 15 int head_rev[N];
 16 int other_rev[M], next_rev[M];
 17 
 18 int cnt[N];
 19 int dis[N];
 20 bool f[N];
 21 
 22 void add (int a, int b, int ln)
 23 {
 24     other[m] = b;
 25     next[m] = head[a];
 26     head[a] = m;
 27 
 28     other_rev[m] = a;
 29     next_rev[m] = head_rev[b];
 30     head_rev[b] = m;
 31 
 32     len[m++= ln;
 33 }
 34 void input ()
 35 {
 36     int i, a, b, ln;
 37     scanf ("%d %d"&n, &m);
 38     memset (head, -1sizeof(head));
 39     memset (head_rev, -1sizeof(head_rev));
 40     i = m;
 41     m = 0;
 42     while (i--)
 43     {
 44         scanf ("%d %d %d"&a, &b, &ln);
 45         add (a, b, ln);
 46     }
 47     scanf ("%d %d %d"&s, &t, &k);
 48 }
 49 
 50 void dij ()
 51 {
 52     int i, j;
 53     memset (f, falsesizeof(f));
 54     for (i=1; i<=n; i++)
 55         dis[i] = INF;
 56     dis[t] = 0;
 57     while (true)
 58     {
 59         i = -1;
 60         for (j=1; j<=n; j++)
 61             if (!f[j] && (i == -1 || dis[j] < dis[i]))
 62                 i = j;
 63         if (i == -1)    break;
 64         f[i] = true;
 65         for (j = head_rev[i]; j!=-1; j=next_rev[j])
 66                 dis[other_rev[j]] = Min (dis[other_rev[j]], dis[i] + len[j]);
 67     }
 68 }
 69 
 70 struct type
 71 {
 72     int i,ln;
 73     type (){}
 74     type (int ii,int ll):i(ii), ln(ll){}
 75 };
 76 bool operator < (const type &a, const type &b)
 77 {
 78     return (a.ln + dis[a.i]) > (b.ln + dis[b.i]);
 79 }
 80 int solve ()
 81 {
 82     dij ();
 83 
 84     memset (cnt, 0sizeof (cnt));
 85     int i,j,ii,ln;
 86 
 87     priority_queue <type> myq;
 88     type now;
 89 
 90     myq.push (type (s,0));
 91     cnt[s] = -1;
 92     while (!myq.empty ())
 93     {
 94         now = myq.top ();
 95         myq.pop ();
 96         i = now.i;
 97         if (++cnt[i] > k)
 98             continue;
 99         if (i == t && cnt[t] == k)
100             return now.ln;
101 
102         ln = now.ln;
103 
104         for (j=head[i]; j!=-1; j=next[j])
105         {
106             ii = other[j];
107             if (cnt[ii] < k)
108                 myq.push (type (ii, ln+len[j]));
109         }
110     }
111     return -1;
112 }
113 
114 int main ()
115 {
116     input ();
117     printf ("%d\n", solve ());
118     return 0;
119 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=1011
Sticks
剪枝好题,中等难度

两个强剪枝
1、如果长度为5的木棍刚好能满足当前块,就没必要尝试用2+3的木棍
2、如果当前块为空,则可指定任意一根木棍放入其内,也没必要尝试其他木棍
POJ 1011
 1 //1011_Sticks ~ alpc02
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int M=70;
 8 
 9 int n,m,len;
10 int a[M];
11 bool f[M];
12 
13 bool cmp(int a,int b){return a>b;}
14 
15 bool DFS(int k,int nowlen,int start)
16 {
17     if (nowlen==0)    return DFS(k-1,len,0);
18     if (k==0)    return true;
19     int i;
20     for (i=start;i<n;++i)
21         if (!f[i] && a[i]<=nowlen)
22         {
23             f[i] = true;
24             if (DFS(k,nowlen-a[i],i+1))    return true;
25             f[i] = false;
26             if (nowlen==a[i] || nowlen==len)
27                 return false;
28         }
29     return false;
30 }
31 
32 int main()
33 {
34     int total,ans,i;
35     while (scanf("%d"&n), n)
36     {
37         total = 0;
38         for (i=0;i<n;++i)
39         {
40             scanf("%d", a+i);
41             total += a[i];
42         }
43         sort(a,a+n,cmp);
44         ans = n+1;
45         while (ans--)
46         {
47             if (total%ans) continue;
48             len = total/ans;
49             memset(f, falsesizeof(f));
50             if (DFS(ans,len,0))    break;
51         }
52         printf("%d\n", total/ans);
53     }
54     return 0;
55 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=1190
生日蛋糕
深搜剪枝,难,《算法艺术与信息学竞赛》P.181

上下界剪枝:
 1、由层数导致的体积上界、下界
最优性剪枝:
1、面积下界 与 当前最优解比较
2、由体积和当前半径导致的最小表面积 S <= 2*V/R (超强)
POJ 1190
 1 //1190_生日蛋糕 ~ alpc02
 2 #include <stdio.h>
 3 #include <string.h>
 4 
 5 #define INF 12345678
 6 #define Max_M 21
 7 #define Max_R 101
 8 #define Max_H 201
 9 
10 int bottom;
11 int vmax[Max_R][Max_H], vmin[Max_M], smin[Max_M];
12 int V[Max_R][Max_H], S[Max_R][Max_H];
13 int ans = INF;
14 
15 void init ()
16 {
17     int i,j;
18 
19     for (i=1; i<Max_R; i++)
20     {
21         for (j=1; j<Max_H; j++)
22         {
23             V[i][j] = i*i*j;
24             S[i][j] = 2*i*j;
25         }
26     }
27 
28     vmin[0= smin[0= 0;
29     for (i=1; i<Max_M; i++)
30     {
31         vmin[i] = vmin[i-1+ V[i][i];
32         smin[i] = smin[i-1+ S[i][i];
33     }
34 
35     for (i=0; i<Max_H; i++)
36         vmax[0][i] = 0;
37     for (i=0; i<Max_R; i++)
38         vmax[i][0= 0;
39 
40     for (i=1; i<Max_R; i++)
41         for (j=1; j<Max_H; j++)
42             vmax[i][j] = vmax[i-1][j-1+ V[i][j];
43 }
44 
45 void search (int v, int s, int r, int h, int m)
46 {
47     if (m == 0)
48     {
49         if (v == 0)
50             ans = s;
51         return ;
52     }
53 
54     int rr, hh;
55     int tv, ts;
56     rr = m;
57     while (s + 2*v/rr >= ans)
58             rr++;
59     for (; rr<=r; rr++)
60     {
61         hh=m;
62         while (vmax[rr][hh] - vmax[rr-m][hh-m] < v)    //最大体积 < 当前体积 
63             hh++;
64         for (; hh<=h; hh++)
65         {
66             tv = v - V[rr][hh];
67             ts = s + S[rr][hh];
68             if (m == bottom)
69                 ts += rr * rr;
70             if (vmin[m-1> tv) //最小体积 > 剩余体积
71                 break;
72             if (ts + smin[m-1>= ans) //最小面积 >= 当前最优解
73                 break;
74             search (tv, ts, rr-1, hh-1, m-1);
75         }
76         if (hh==m)
77             break;
78     }
79 }
80 int main()
81 {
82     init ();
83     int v,m;
84     scanf ("%d"&v);
85     scanf ("%d"&m);
86     bottom = m;
87     search (v, 0, Max_R, Max_H, m);
88     if (ans == INF)
89         ans = 0;
90     printf ("%d\n", ans);
91     return 0;
92 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=1324
Holedox Moving
广搜,A*搜会快一些,中等难度

关键点在于怎么判重、怎么存储蛇:蛇头 + 后面每个点相对于前一点的方向(即0、1、2、3四元值),因此状态空间 20*20*4^(8-1) = 6553600,因此可以用数组判重。
POJ 1324
  1 //1324_HoledoxMoving ~ alpc02
  2 #pragma warning (disable :4786)
  3 #include <stdio.h>
  4 #include <map>
  5 #include <queue>
  6 #include <algorithm>
  7 using namespace std;
  8 
  9 const int M = 6553600;
 10 const int N = 20;
 11 const int L = 8;
 12 
 13 int m,n,l;
 14 bool p[N][N];
 15 int y[L], x[L];
 16 
 17 struct forQ
 18 {
 19     int s;
 20     int g,h;
 21 };
 22 bool operator < (const forQ &a, const forQ &b)
 23 {
 24     return (a.g + a.h) > (b.g + b.h);
 25 }
 26 
 27 bool input ()
 28 {
 29     scanf ("%d %d %d"&m, &n, &l);
 30     if (m==0 && n==0 && l==0)    return false;
 31     
 32     memset (p, truesizeof (p));
 33     int i, k, ty, tx;
 34     for (i=0; i<l; i++)
 35     {
 36         scanf ("%d %d", y+i, x+i);
 37         y[i]--;
 38         x[i]--;
 39     }
 40     scanf ("%d"&k);
 41     while (k--)
 42     {
 43         scanf ("%d %d"&ty, &tx);
 44         p[ty-1][tx-1= false;
 45     }
 46     return true;
 47 }
 48 
 49 priority_queue <forQ> myq;
 50 int min_step[M];
 51 
 52 int ty[] = {1,0,0,-1};
 53 int tx[] = {0,1,-1,0};
 54 
 55 void init ()
 56 {
 57     memset (min_step, -1sizeof(min_step[0]) * 400 * (1<<(2*(l-1))) );
 58     while (!myq.empty ())
 59         myq.pop ();
 60 }
 61 void In (int &s, int *y, int *x)
 62 {
 63     s = 0;
 64     int i, j;
 65     for (i=l-1; i>=1; i--)
 66     {
 67         for (j=0; ; j++)
 68             if (y[i-1+ ty[j] == y[i] && x[i-1+ tx[j] == x[i])
 69                 break;
 70         s = s * 4 + j;
 71     }
 72     s = s*20 + y[0];
 73     s = s*20 + x[0];
 74 }
 75 void Out (int s, int *y, int *x)
 76 {
 77     int i, j;
 78 
 79     x[0= s % 20;
 80     s /= 20;
 81     y[0= s % 20;
 82     s /= 20;
 83     for (i=1; i<l; i++)
 84     {
 85         j = s % 4;
 86         s = s / 4;
 87         y[i] = y[i-1+ ty[j];
 88         x[i] = x[i-1+ tx[j];
 89     }
 90 }
 91 struct type
 92 {
 93     int y,x;
 94     type () {}
 95     type (int yy,int xx): y(yy), x(xx) {}
 96 };
 97 bool reachable (int y,int x)
 98 {
 99     if (y == 0 && x == 0)
100         return true;
101     bool f[N][N];
102     memset (f, falsesizeof(f));
103     queue <type> q;
104     type now;
105     int yy,xx,t;
106 
107     q.push (type(y,x));
108     f[y][x] = true;
109 
110     while (!q.empty ())
111     {
112         now = q.front ();
113         q.pop ();
114         for (t=0; t<4; t++)
115         {
116             yy = now.y + ty[t];
117             xx = now.x + tx[t];
118             if (yy >= 0 && yy < m && xx >= 0 && xx < n && !f[yy][xx] && p[yy][xx])
119             {
120                 if (yy == 0 && xx == 0)
121                     return true;
122                 f[yy][xx] = true;
123                 q.push (type(yy,xx));
124             }
125         }
126     }
127     return false;
128 }
129 int solve ()
130 {
131     if (!reachable (y[0],x[0]))
132         return -1;
133     init ();
134     
135     int y1[8],x1[8];
136     int y2[8],x2[8];
137     
138     int s;
139     forQ now;
140 
141     In (now.s, y, x);
142     now.g = 0;
143     now.h = y[0+ x[0];
144     
145     myq.push (now);
146     min_step[now.s] = 0;
147     
148     int yy,xx,t,i;
149 
150     while (!myq.empty())
151     {
152         now = myq.top ();
153         myq.pop ();
154         if (min_step[now.s] == -2)
155             continue;
156         min_step[now.s] = -2;
157 
158         s = now.s;
159         Out (s, y1, x1);
160         if (y1[0== 0 && x1[0== 0)
161             return now.g;
162 
163         now.g ++;
164         for (i=0; i<l; i++)
165             p[y1[i]][x1[i]] = false;
166         for (t=0; t<4; t++)
167         {
168             for (i=l-1; i>=1; i--)
169             {
170                 y2[i] = y1[i-1];
171                 x2[i] = x1[i-1];
172             }
173             yy = y1[0+ ty[t];
174             xx = x1[0+ tx[t];
175             if (yy >= 0 && yy < m && xx >= 0 && xx < n && p[yy][xx])
176             {
177                 now.s = (( (s/400 % (1<<(2*(l-2))) ) * 4+ (3-t) ) * 400 + yy * 20 + xx;
178                 if (min_step[now.s] == -1 || min_step[now.s] > now.g)
179                 {
180                     now.h = yy + xx;
181                     min_step[now.s] = now.g;
182                     myq.push (now);
183                 }
184             }
185         }
186         for (i=0; i<l; i++)
187             p[y1[i]][x1[i]] = true;
188     }
189     return -1;
190 }
191 
192 int main()
193 {
194     int Ca = 0;
195     while (input ())
196     {
197         printf ("Case %d: %d\n"++Ca, solve ());
198     }
199     return 0;
200 }


http://acm.pku.edu.cn/JudgeOnline/problem?id=2044
Weather Forecast
用深搜做的,搜到一个解即可退出,中等难度

像上个题一样,关键点还是在于怎么判重、怎么存储状态(当前天是第几天 以及 前6天的天气状况):最后1天云的位置(0、1、2……8) + 云的变化方向(0、1、2、3、4),状态空间5^5 * 9 * 365 = 10265625,开数组还是非常不错的。
POJ 2044
  1 //2044_WeatherForecast ~ alpc02
  2 #pragma warning (disable:4786)
  3 #include <stdio.h>
  4 #include <queue>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int D = 365;
  9 const int N = 9;
 10 const int M = 5*5*5*5*5*9*D;
 11 
 12 bool flag[M];
 13 
 14 int rain[N][4= 
 15 {
 16     {1,2,5,6},
 17     {2,3,6,7},
 18     {3,4,7,8},
 19     {5,6,9,10},
 20     {6,7,10,11},
 21     {7,8,11,12},
 22     {9,10,13,14},
 23     {10,11,14,15},
 24     {11,12,15,16},
 25 };
 26 bool israin[N][17];
 27 
 28 bool couldgo[N][N] = 
 29 {
 30     {1,1,1,1,0,0,1,0,0},
 31     {1,1,1,0,1,0,0,1,0},
 32     {1,1,1,0,0,1,0,0,1},
 33     {1,0,0,1,1,1,1,0,0},
 34     {0,1,0,1,1,1,0,1,0},
 35     {0,0,1,1,1,1,0,0,1},
 36     {1,0,0,1,0,0,1,1,1},
 37     {0,1,0,0,1,0,1,1,1},
 38     {0,0,1,0,0,1,1,1,1},
 39 };
 40 int go[N][5];
 41 
 42 int d;
 43 bool f[D][N];
 44 
 45 void init ()
 46 {
 47     memset (israin, falsesizeof(israin));
 48     int i, j, k;
 49     for (i=0; i<N; i++)
 50     {
 51         for (j=0; j<4; j++)
 52             israin[i] [rain[i][j]] = true;
 53     }
 54     for (i=0; i<N; i++)
 55     {
 56         k = 0;
 57         for (j=0; j<9; j++)
 58             if (couldgo[i][j])
 59                 go[i][k++= j;
 60     }
 61 }
 62 bool input ()
 63 {
 64     int sun[17];
 65     int i, j, k;
 66     scanf ("%d"&d);
 67     if (d == 0)
 68         return false;
 69     for (i=0; i<d; i++)
 70     {
 71         for (j=1; j<=16; j++)
 72         {
 73             scanf ("%d", sun+j);
 74         }
 75         for (j=0; j<9; j++)
 76         {
 77             for (k=0; k<4; k++)
 78                 if (sun[rain[j][k]])
 79                     break;
 80             f[i][j] = (k==4);
 81         }
 82     }
 83     return true;
 84 }
 85 
 86 struct Go
 87 {
 88     int j, dif;
 89 };
 90 bool operator < (const Go &a, const Go &b)
 91 {
 92     return a.dif < b.dif;
 93 }
 94 
 95 int dfs (int s)
 96 {
 97     if (flag[s])
 98         return 0;
 99     flag[s] = true;
100     bool six[17= {0};
101 
102     int i, j, k, t, new_s, pre, temp;
103     t = s % d;
104     s /= d;
105 
106     if (t == 0)
107     {
108         return 1;
109     }
110 
111     int need[12], top=0;
112 
113     if (t >= 6)
114     {
115         temp = s;
116         pre = temp % 9;
117         temp /= 9;
118         for (k=0; k<4; k++)
119             six[rain[pre][k]] = true;
120         for (i=0; i<5; i++)
121         {
122             j = go[pre][temp % 5];
123             temp /= 5;
124             for (k=0; k<4; k++)
125                 six[rain[j][k]] = true;
126             pre = j;
127         }
128         for (i=1; i<=16; i++)
129             if (!six[i])
130                 need[top++= i;
131     }
132     pre = s % 9;
133     s /= 9;
134     int p, now;
135     Go go_list[9];
136     int go_top = 0;
137     for (j=0; j<9; j++)
138     {
139         if (!f[t][j] || !couldgo[pre][j])
140             continue;
141 
142         for (k=0; k<top; k++)
143             if (!israin[j][need[k]])
144                 break;
145         if (k == top)
146         {
147             go_list[go_top].j = j;
148             go_list[go_top].dif = 0;
149             now = pre;
150             temp = s;
151             do
152             {
153                 if (j != now)
154                     ++go_list[go_top].dif;
155                 now = go[now] [temp % 5];
156                 temp /= 5;
157             }while (temp);
158             go_top++;
159         }
160     }
161     sort (go_list, go_list + go_top);
162     for (i=0; i<go_top; i++)
163     {
164         j = go_list[i].j;
165         for (p=0; p<5; p++)
166             if (go[j][p] == pre)
167                 break;
168         new_s = (s % 625* 5 + p;
169         new_s = new_s * 9 + j;
170         new_s = new_s * d + (t+1% d;
171         if (dfs (new_s))
172             return 1;
173     }
174     return 0;
175 }
176 int solve ()
177 {
178     if (!f[0][4])
179         return false;
180     memset (flag, false5*5*5*5*5*9*d*sizeof(flag[0]));
181     return dfs (4*d+1%d);
182 }
183 
184 int main()
185 {
186     init ();
187     while (input ())
188     {
189         printf ("%d\n", solve ());
190     }
191     return 0;
192 }

 

你可能感兴趣的:(搜索题集锦(无限更新中……))