HDU 搜索进阶专题

去年听ReDow讲A*,IDA*,当时小菜(现在也是),就没把那些东西列在学习范围内,前些天LCY让我讲搜索进阶,就做了几题,分享下做题感受~~

    

HDU 1043 Eight

涉及到人生完不完整的一道题,有位大神总结出了八数码的8重境界,可见其经典程度无出其右~~

A*: 因为每次移动都会影响一个点的曼哈顿距离(不算x),构造h()为所有数字块的曼哈顿距离和,用逆序数hash(算x),根据逆序数奇偶性(不算x)减掉无法到达的情况,A*跑了656ms,POJ 16ms,在构造优先队列时当f相同时按照g值从大到小排序,这样又是一个很给力的减枝,HDU 468ms,POJ 0ms 
View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 usingnamespace std;
5
6 struct S{
7 char maze[3][3];
8 int x,y;
9 int g,h,f;
10 S(){}
11 S(const S& ts){
12 for(int i=0;i<3;i++){
13 for(int j=0;j<3;j++){
14 maze[i][j]=ts.maze[i][j];
15 }
16 }
17 x=ts.x; y=ts.y;
18 g=ts.g; h=ts.h; f=ts.f;
19 }
20 friend booloperator< (const S& a,const S& b){
21 if(a.f==b.f) return a.g<b.g;
22 return a.f>b.f;
23 }
24 }s;
25 constint fac[]={1,1,2,6,24,120,720,5040,40320};
26 bool vis[363000];
27 int pre[363000];
28 char op[363000];
29
30 inline int inv_hash(S ts){
31 char str[10]; int ans=0;
32 for(int i=0;i<3;i++){
33 for(int j=0;j<3;j++){
34 str[i*3+j]=ts.maze[i][j];
35 int cnt=0;
36 for(int k=i*3+j-1;k>=0;k--){
37 if(str[k]>str[i*3+j]) cnt++;
38 }
39 ans+=fac[i*3+j]*cnt;
40 }
41 }
42 return ans;
43 }
44
45 constint pos[][2]={{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
46 inline int ABS(int x){return x<0?-x:x;}
47 inline int h(S ts){
48 int val=0;
49 for(int i=0;i<3;i++){
50 for(int j=0;j<3;j++){
51 if(ts.maze[i][j]=='x') continue;
52 int c=ts.maze[i][j]-'1';
53 val+=ABS(pos[c][0]-i)+ABS(pos[c][1]-j);
54 }
55 }
56 return val;
57 }
58
59 constint dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
60 bool bfs(){
61 memset(vis,false,sizeof(vis));
62
63 priority_queue<S> que;
64 que.push(s);
65 while(!que.empty()){
66 S u=que.top(); que.pop();
67 int ihu=inv_hash(u);
68
69 for(int i=0;i<4;i++){
70 S v=u;
71 v.x+=dir[i][0];
72 v.y+=dir[i][1];
73 if(v.x<0||v.y<0||v.x>=3||v.y>=3) continue;
74 v.maze[u.x][u.y]=u.maze[v.x][v.y];
75 v.maze[v.x][v.y]='x';
76 v.g+=1; v.h=h(v); v.f=v.g+v.h;
77 int ihv=inv_hash(v);
78 if(vis[ihv]) continue;
79 vis[ihv]=true;
80 pre[ihv]=ihu;
81 if(i==0) op[ihv]='d';
82 elseif(i==1) op[ihv]='r';
83 elseif(i==2) op[ihv]='u';
84 elseif(i==3) op[ihv]='l';
85 if(ihv==0) returntrue;
86 que.push(v);
87 }
88 }
89 returnfalse;
90 }
91
92 inline bool inv_check(){
93 char str[10];
94 int cnt=0;
95 for(int i=0;i<3;i++){
96 for(int j=0;j<3;j++){
97 str[i*3+j]=s.maze[i][j];
98 if(str[i*3+j]=='x') continue;
99 for(int k=i*3+j-1;k>=0;k--){
100 if(str[k]=='x') continue;
101 if(str[k]>str[i*3+j]) cnt++;
102 }
103 }
104 }
105 return!(cnt&1);
106 }
107
108 charin[100];
109 char stk[100];
110 int main(){
111 while(gets(in)){
112 for(int i=0,x=0,y=0;in[i];i++){
113 if((in[i]<='9'&&in[i]>='0')||in[i]=='x'){
114 s.maze[x][y]=in[i];
115 if(in[i]=='x'){s.x=x;s.y=y;}
116 y++; if(y==3) y=0,x++;
117 }
118 }
119
120 if(!inv_check()){
121 puts("unsolvable");
122 continue;
123 }
124 s.g=0; s.h=h(s); s.f=s.h;
125
126 int shash=inv_hash(s);
127 if(shash==0){puts(""); continue;}
128 bfs();
129 int top=-1,thash=0;
130 while(thash!=shash){
131 stk[++top]=op[thash];
132 thash=pre[thash];
133 }
134 for(int i=top;i>=0;i--){
135 putchar(stk[i]);
136 }
137 puts("");
138 }
139 }

  

单广预处理: 从最终状态向所有状态搜索,记录前驱,然后直接输出就好了,HDOJ 93ms POJ 313ms
View Code
 1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 usingnamespace std;
5
6 struct S{
7 char maze[3][3];
8 int x,y;
9
10 S(){}
11 S(constchar*str){
12 for(int i=0,tx=0,ty=0;str[i];i++){
13 if((str[i]<='9'&&str[i]>='0')||str[i]=='x'){
14 maze[tx][ty]=str[i];
15 if(str[i]=='x'){x=tx;y=ty;}
16 ty++;if(ty==3){ty=0;tx++;}
17 }
18 }
19 }
20 };
21 int pre[363000];
22 char op[363000];
23
24 constint fac[]={1,1,2,6,24,120,720,5040,40320};
25 bool vis[363000];
26 inline int inv_hash(S ts){
27 char str[10]; int ans=0;
28 for(int i=0;i<3;i++){
29 for(int j=0;j<3;j++){
30 str[i*3+j]=ts.maze[i][j];
31 int cnt=0;
32 for(int k=i*3+j-1;k>=0;k--){
33 if(str[k]>str[i*3+j]) cnt++;
34 }
35 ans+=fac[i*3+j]*cnt;
36 }
37 }
38 return ans;
39 }
40
41 S s;
42 constint dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
43 constchar cdir[]="dulr";
44 void bfs(){
45 memset(vis,false,sizeof(vis));
46 memset(pre,-1,sizeof(pre));
47
48 queue<S> que;
49 que.push(s);
50 while(!que.empty()){
51 S u=que.front(); que.pop();
52 int ihu=inv_hash(u);
53 for(int i=0;i<4;i++){
54 S v=u;
55 v.x+=dir[i][0];
56 v.y+=dir[i][1];
57 if(v.x<0||v.y<0||v.x>=3||v.y>=3) continue;
58 v.maze[u.x][u.y]=v.maze[v.x][v.y];
59 v.maze[v.x][v.y]='x';
60 int ihv=inv_hash(v);
61 if(vis[ihv]) continue;
62 vis[ihv]=true;
63 pre[ihv]=ihu;
64 op[ihv]=cdir[i];
65 que.push(v);
66 }
67 }
68 }
69
70 charin[100];
71 char stk[100];
72 int main(){
73 s=S("12345678x");
74 bfs();
75
76 while(gets(in)){
77 s=S(in);
78 int ihs=inv_hash(s);
79 if(pre[ihs]==-1){puts("unsolvable");continue;}
80 if(ihs==0){puts("");continue;}
81 int top=-1,tmp=ihs;
82 while(tmp){
83 putchar(op[tmp]);
84 tmp=pre[tmp];
85 }
86 puts("");
87 }
88 }

  

IDA*: 和A*相同的h()函数,跑了1s+,POJ 63ms,500k的内存是其优势

View Code
  1 #include<cstdio>
2 #include<cstring>
3 usingnamespace std;
4
5 struct S{
6 char maze[3][3];
7 int x,y;
8 int g,h,f;
9 S(){}
10 S(const S& ts){
11 for(int i=0;i<3;i++){
12 for(int j=0;j<3;j++){
13 maze[i][j]=ts.maze[i][j];
14 }
15 }
16 x=ts.x; y=ts.y;
17 }
18
19 void show(){
20 for(int i=0;i<3;i++){
21 for(int j=0;j<3;j++){
22 putchar(maze[i][j]);
23 }puts("");
24 }
25 }
26 };
27
28 constint pos[][2]={{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
29 inline int ABS(int x){
30 if(x<0) return-x;
31 elsereturn x;
32 }
33 inline int h(S ts){
34 int val=0;
35 for(int i=0;i<3;i++){
36 for(int j=0;j<3;j++){
37 if(ts.maze[i][j]=='x') continue;
38 int c=ts.maze[i][j]-'1';
39 val+=ABS(pos[c][0]-i)+ABS(pos[c][1]-j);
40 }
41 }
42 return val;
43 }
44
45 int fac[]={1,1,2,6,24,120,720,5040,40320};
46 inline int inv_hash(S ts){
47 char str[10]; int ans=0;
48 for(int i=0;i<3;i++){
49 for(int j=0;j<3;j++){
50 str[i*3+j]=ts.maze[i][j];
51 int cnt=0;
52 for(int k=i*3+j-1;k>=0;k--){
53 if(str[k]>str[i*3+j]) cnt++;
54 }
55 ans+=fac[i*3+j]*cnt;
56 }
57 }
58 return ans;
59 }
60
61 int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
62 int ans[50],deep;
63 bool vis[363000];
64 S ts;
65 bool dfs(int d){
66 if(h(ts)==0) returntrue;
67 if(h(ts)+d>deep) returnfalse;
68
69 int x=ts.x;
70 int y=ts.y;
71 for(int i=0;i<4;i++){
72 int tx=ts.x+dir[i][0];
73 int ty=ts.y+dir[i][1];
74 if(tx<0||ty<0||tx>=3||ty>=3) continue;
75 ts.maze[x][y]=ts.maze[tx][ty];
76 ts.maze[tx][ty]='x';
77 int tmp=inv_hash(ts);
78 if(vis[tmp]){
79 ts.maze[tx][ty]=ts.maze[x][y];
80 ts.maze[x][y]='x';
81 continue;
82 }
83 vis[tmp]=true;
84 ts.x=tx; ts.y=ty;
85 ans[d]=i;
86 if(dfs(d+1)) returntrue;
87 vis[tmp]=false;
88 ts.x=x; ts.y=y;
89 ts.maze[tx][ty]=ts.maze[x][y];
90 ts.maze[x][y]='x';
91 }
92 returnfalse;
93 }
94
95 S s;
96 bool inv_check(){
97 char str[10];
98 int cnt=0;
99 for(int i=0;i<3;i++){
100 for(int j=0;j<3;j++){
101 str[i*3+j]=s.maze[i][j];
102 if(str[i*3+j]=='x') continue;
103 for(int k=i*3+j-1;k>=0;k--){
104 if(str[k]=='x') continue;
105 if(str[k]>str[i*3+j]) cnt++;
106 }
107 }
108 }
109 return!(cnt&1);
110 }
111
112
113 charin[100];
114 int main(){
115 while(gets(in)){
116 for(int i=0,x=0,y=0;in[i];i++){
117 if((in[i]<='9'&&in[i]>='0')||in[i]=='x'){
118 s.maze[x][y]=in[i];
119 if(in[i]=='x'){s.x=x;s.y=y;}
120 y++;
121 if(y==3) y=0,x++;
122 }
123 }
124 if(!inv_check()){ puts("unsolvable"); continue;}
125 memset(vis,false,sizeof(vis));
126 vis[inv_hash(s)]=true;
127 ts=s; deep=0;
128 while(true){
129 if(dfs(0)) break;
130 deep++;
131 }
132 for(int i=0;i<deep;i++){
133 if(ans[i]==0) putchar('d');
134 elseif(ans[i]==1) putchar('r');
135 elseif(ans[i]==2) putchar('u');
136 elseif(ans[i]==3) putchar('l');
137 }
138 puts("");
139 }
140 }

  

HDU 1667 The Rotation Game

IDA*的入门题目,状态过多容易超内存,正好体现了IDA*的优势,每次操作移动能使一个数字进入中间的八个位置,所以构造h()=8-max(1,2,3在中间8个位置的个数),自己的写的太挫了,跑了1s多,后来问ReDow大神要了代码,171ms

View Code
  1 #include<cstdio>
2 #include<cstring>
3 usingnamespace std;
4
5 int maze[10][10]={0};
6 bool check(){
7 if(maze[3][3]!=maze[3][4]) returnfalse;
8 if(maze[3][3]!=maze[3][5]) returnfalse;
9 if(maze[3][3]!=maze[4][3]) returnfalse;
10 if(maze[3][3]!=maze[5][3]) returnfalse;
11 if(maze[3][3]!=maze[5][4]) returnfalse;
12 if(maze[3][3]!=maze[5][5]) returnfalse;
13 if(maze[3][3]!=maze[4][5]) returnfalse;
14 returntrue;
15 }
16
17 void roA(){
18 int tmp=maze[1][3];
19 for(int i=1;i<=6;i++) maze[i][3]=maze[i+1][3];
20 maze[7][3]=tmp;
21 }
22
23 void roB(){
24 int tmp=maze[1][5];
25 for(int i=1;i<=6;i++) maze[i][5]=maze[i+1][5];
26 maze[7][5]=tmp;
27 }
28
29 void roC(){
30 int tmp=maze[3][7];
31 for(int i=7;i>=2;i--) maze[3][i]=maze[3][i-1];
32 maze[3][1]=tmp;
33 }
34
35 void roD(){
36 int tmp=maze[5][7];
37 for(int i=7;i>=2;i--) maze[5][i]=maze[5][i-1];
38 maze[5][1]=tmp;
39 }
40
41 void roE(){
42 int tmp=maze[7][5];
43 for(int i=7;i>=2;i--) maze[i][5]=maze[i-1][5];
44 maze[1][5]=tmp;
45 }
46
47 void roF(){
48 int tmp=maze[7][3];
49 for(int i=7;i>=2;i--) maze[i][3]=maze[i-1][3];
50 maze[1][3]=tmp;
51 }
52
53 void roG(){
54 int tmp=maze[5][1];
55 for(int i=1;i<=6;i++) maze[5][i]=maze[5][i+1];
56 maze[5][7]=tmp;
57 }
58
59 void roH(){
60 int tmp=maze[3][1];
61 for(int i=1;i<=6;i++) maze[3][i]=maze[3][i+1];
62 maze[3][7]=tmp;
63 }
64
65
66 int h(){
67 int a[4]={0};
68 for(int i=3;i<=5;i++){
69 a[maze[3][i]]++;
70 a[maze[5][i]]++;
71 }
72 a[maze[4][3]]++;
73 a[maze[4][5]]++;
74
75 int max=0;
76 for(int i=1;i<=3;i++){
77 if(max<a[i]) max=a[i];
78 }
79 return8-max;
80 }
81
82 char ans[100];
83 int deep;
84 bool dfs(int d){
85 if(d==deep) return check();
86 if(h()+d>deep) returnfalse;
87 roA();
88 ans[d]='A';
89 if(dfs(d+1)) returntrue;
90 roF();
91
92 roB();
93 ans[d]='B';
94 if(dfs(d+1)) returntrue;
95 roE();
96
97 roC();
98 ans[d]='C';
99 if(dfs(d+1)) returntrue;
100 roH();
101
102 roD();
103 ans[d]='D';
104 if(dfs(d+1)) returntrue;
105 roG();
106
107 roE();
108 ans[d]='E';
109 if(dfs(d+1)) returntrue;
110 roB();
111
112 roF();
113 ans[d]='F';
114 if(dfs(d+1)) returntrue;
115 roA();
116
117 roG();
118 ans[d]='G';
119 if(dfs(d+1)) returntrue;
120 roD();
121
122 roH();
123 ans[d]='H';
124 if(dfs(d+1)) returntrue;
125 roC();
126 returnfalse;
127 }
128
129 int main(){
130 for(int i=1;i<=7;i++) maze[3][i]=maze[5][i]=1;
131 for(int i=1;i<=7;i++) maze[i][3]=maze[i][5]=1;
132 while(true){
133 for(int i=1;i<=7;i++){
134 for(int j=1;j<=7;j++){
135 if(maze[i][j]==0) continue;
136 scanf("%d",&maze[i][j]);
137 if(maze[i][j]==0) return0;
138 }
139 }
140 if(check()){
141 puts("No moves needed");
142 printf("%d\n",maze[3][3]);
143 continue;
144 }
145 deep=1;
146 while(true){
147 if(dfs(0)) break;
148 deep++;
149 }
150
151 for(int i=0;i<deep;i++) putchar(ans[i]);
152 puts("");
153 printf("%d\n",maze[3][3]);
154 }
155 return0;
156 }

    

HDU 2234 无题I

IDA*,开始写挫了,加了A*还是超时,又乱搞了好久才过,后来重写了一遍,2s+;每次移动改变四个点的位置,即h()=(最少可能的横向或纵向不在位置上的点的个数+3)/4 );看到CY 1.3s 求代码得知是普通的dfs,数据水了...

View Code
  1 #include<cstdio>
2 #include<cstring>
3 usingnamespace std;
4
5 char maze[5][5];
6 inline void roL(int x){
7 char t=maze[x][0];
8 maze[x][0]=maze[x][1];
9 maze[x][1]=maze[x][2];
10 maze[x][2]=maze[x][3];
11 maze[x][3]=t;
12 }
13 inline void roR(int x){
14 char t=maze[x][3];
15 maze[x][3]=maze[x][2];
16 maze[x][2]=maze[x][1];
17 maze[x][1]=maze[x][0];
18 maze[x][0]=t;
19 }
20 inline void roU(int x){
21 char t=maze[0][x];
22 maze[0][x]=maze[1][x];
23 maze[1][x]=maze[2][x];
24 maze[2][x]=maze[3][x];
25 maze[3][x]=t;
26 }
27 inline void roD(int x){
28 int t=maze[3][x];
29 maze[3][x]=maze[2][x];
30 maze[2][x]=maze[1][x];
31 maze[1][x]=maze[0][x];
32 maze[0][x]=t;
33 }
34
35 bool flag[5];
36 inline int h(){
37 int val=20;
38 int tmp=0;
39 for(int i=0;i<4;i++){
40 int cnt=4;
41 memset(flag,false,sizeof(flag));
42 for(int j=0;j<4;j++){
43 if(flag[maze[i][j]-'1']) continue;
44 flag[maze[i][j]-'1']=true;
45 cnt--;
46 }
47 tmp+=3-cnt;
48 }
49 if(tmp<val) val=tmp;
50 tmp=0;
51 for(int i=0;i<4;i++){
52 int cnt=4;
53 memset(flag,false,sizeof(flag));
54 for(int j=0;j<4;j++){
55 if(flag[maze[j][i]-'1']) continue;
56 flag[maze[j][i]-'1']=true;
57 cnt--;
58 }
59 tmp+=3-cnt;
60 }
61 if(tmp<val) val=tmp;
62 return val;
63 }
64
65 int deep;
66 bool dfs(int d){
67 if(d==deep&&h()==0) returntrue;
68 if(d+(h()+3)/4>deep) returnfalse;
69
70 for(int i=0;i<4;i++){
71
72 roL(i);
73 if(dfs(d+1)) returntrue;
74 roR(i);
75
76 roR(i);
77 if(dfs(d+1)) returntrue;
78 roL(i);
79
80 roU(i);
81 if(dfs(d+1)) returntrue;
82 roD(i);
83
84 roD(i);
85 if(dfs(d+1)) returntrue;
86 roU(i);
87 }
88 returnfalse;
89 }
90
91 inline voidin(char& c){
92 c=getchar();
93 while(c<=32) c=getchar();
94 }
95
96 int main(){
97 int t;
98 scanf("%d",&t);
99 while(t--){
100 for(int i=0;i<4;i++){
101 for(int j=0;j<4;j++){
102 in(maze[i][j]);
103 }
104 }
105 deep=0;
106 while(deep<=5){
107 if(dfs(0)) break;
108 deep++;
109 }
110 if(deep<=5) printf("%d\n",deep);
111 else puts("-1");
112 }
113 }

  

HDU 1560 DNA sequence

IDA*: 容易看出最少步数肯定是大于等于最大字符长度的,所以就构造 h() 为所有剩余长度的最大值,2s
View Code
 1 #include<cstdio>
2 #include<cstring>
3 #include<bitset>
4 usingnamespace std;
5 #define MAX(a,b) (a>b?a:b)
6
7 char code[]="ATGC";
8 int pos[10],n;
9 int h(){
10 int ans=0;
11 for(int i=0;i<n;i++){
12 ans=MAX(pos[i],ans);
13 }
14 return ans;
15 }
16
17 int deep;
18 char maze[10][8];
19 bool dfs(int d){
20 int th=h();
21 if(th==0) returntrue;
22 if(d+th>deep) returnfalse;
23 for(int i=0;i<4;i++){
24 bool flag=false;
25 int tpos[10];
26 for(int j=0;j<n;j++){
27 tpos[j]=pos[j];
28 if(pos[j]==0) continue;
29 if(maze[j][pos[j]-1]==code[i]){
30 pos[j]--;
31 flag=true;
32 }
33 }
34
35 if(flag){
36 if(dfs(d+1)) returntrue;
37 }
38 for(int j=0;j<n;j++){
39 pos[j]=tpos[j];
40 }
41 }
42 returnfalse;
43 }
44
45 int main(){
46 int t;
47 scanf("%d",&t);
48 while(t--){
49 scanf("%d",&n);
50 for(int i=0;i<n;i++){
51 scanf("%s",maze[i]);
52 pos[i]=strlen(maze[i]);
53 }
54 deep=0;
55 while(true){
56 if(dfs(0)) break;
57 deep++;
58 }
59 printf("%d\n",deep);
60 }
61 }

    

单广: 去年写了一个很挫很挫的单广,在各种TLE,MLE,RE之后终于4984ms过掉了(限5s),今年吓怕了不敢写,后来向hh要了他的125ms的代码,单广,就模仿hh的代码,很装逼的用8进制压缩,结果状态由300w骤升至1500w,还要用bitset来hash,跑400+ms,就不拿出来丢人了;hh的代码直接开int进行hash,每组cas的hash值不同,这样就省去了每次初始化的消耗,hh的代码~

View Code
 1 #include "stdio.h"
2 #include "string"
3 #define M 1679616+100000
4 struct H{
5 int st;
6 int len;
7 }q[M];
8 int hash[M],cas =1;
9 int n , end ,len;
10 char str[8][8];
11 char ku[] ="ACGT";
12 int bfs() {
13 int head,tail,i,st;
14 int pos[8];
15 q[0].len =0;
16 q[0].st =0;
17 head = tail =0;
18 while(head <= tail) {
19 st = q[head].st;
20 for(i =0 ; i < n ; i ++) {
21 pos[i] = st%len;
22 st/=len;
23 }
24 for(int j =0 ; j <4 ; j ++) {
25 st =0;
26 for(i = n-1; i >=0 ;i --) {
27 st = st * len + pos[i] + (str[i][pos[i]] == ku[j]);
28 }
29 if(hash[st] == cas) {
30 continue;
31 }
32 if(st == end) {
33 return q[head].len +1;
34 }
35 hash[st] = cas;
36 tail ++;
37 q[tail].len = q[head].len +1;
38 q[tail].st = st;
39 }
40 head ++;
41 }
42 return-1;
43 }
44 int main() {
45 int T , i ;
46 scanf("%d",&T);
47 while(T --) {
48 scanf("%d",&n);
49 len =0;
50 for(i =0 ; i < n ; i ++) {
51 scanf("%s",str[i]);
52 if(strlen(str[i]) > len) {
53 len = strlen(str[i]);
54 }
55 }
56 len ++;
57 end =0;
58 for(i = n-1 ; i >=0 ; i --) {
59 end = end * len + strlen(str[i]);
60 }
61 printf("%d\n",bfs());
62 cas ++;
63 }
64 return0;
65 }

  

HDU 1813  Escape from Tetris

IDA*的好题目,开始时没想到A*方法,就直接暴力的提交了一次,如愿超时,随便YY了一组case就跑不出结果,然后想到可以求出某个位置逃出的最少步数,然后在构造 h() 为所有点逃离迷宫的最少步数的最大值,然后很容易就能A掉了

View Code
  1 #include<cstdio>
2 #include<cstring>
3 usingnamespace std;
4
5 int n;
6 bool maze[10][10];
7 int dir[4][2]={{0,1},{-1,0},{1,0},{0,-1}};
8
9 int ans[100];
10 int dis[10][10];
11 int deep;
12
13 struct S{
14 bool maze[10][10];
15 S(){memset(maze,false,sizeof(maze));}
16 }s;
17
18 inline bool h(int d,S ts){
19 for(int i=1;i<n-1;i++){
20 for(int j=1;j<n-1;j++){
21 if(!ts.maze[i][j]) continue;
22 if(dis[i][j]+d>deep){
23 returnfalse;
24 }
25 }
26 }
27 returntrue;
28 }
29
30 bool dfs(int d,S tu){
31 if(!h(d,tu)) returnfalse;
32 if(d==deep) returntrue;
33 for(int i=0;i<4;i++){
34 S tv;
35 for(int ii=1;ii<n-1;ii++){
36 for(int jj=1;jj<n-1;jj++){
37 if(!maze[ii][jj]) continue;
38 int tx=ii-dir[i][0];
39 int ty=jj-dir[i][1];
40 tv.maze[ii][jj]=tu.maze[tx][ty];
41 tx=ii+dir[i][0];
42 ty=jj+dir[i][1];
43 if(maze[tx][ty]) continue;
44 tv.maze[ii][jj]|=tu.maze[ii][jj];
45 }
46 }
47 ans[d]=i;
48 if(dfs(d+1,tv)) returntrue;
49 }
50 returnfalse;
51 }
52
53 int que[1000][2];
54 void bfs(int x,int y){
55 dis[x][y]=0;
56 int ss=0,ee=0;
57 que[0][0]=x;
58 que[0][1]=y;
59 while(ss<=ee){
60 int ux=que[ss][0];
61 int uy=que[ss][1];
62 ss++;
63 for(int i=0;i<4;i++){
64 int tx=ux+dir[i][0];
65 int ty=uy+dir[i][1];
66 if(tx<=0||ty<=0||tx>=n-1||ty>=n-1) continue;
67 if(!maze[tx][ty]) continue;
68 if(dis[tx][ty]<=dis[ux][uy]+1) continue;
69 dis[tx][ty]=dis[ux][uy]+1;
70 ee++;
71 que[ee][0]=tx;
72 que[ee][1]=ty;
73 }
74 }
75 }
76
77 inline voidin(bool& val){
78 charin=getchar();
79 while(in<=32) in=getchar();
80 val=(in=='0');
81 }
82
83 int main(){
84 bool flag=false;
85 while(~scanf("%d",&n)){
86 for(int i=0;i<n;i++){
87 for(int j=0;j<n;j++){
88 in(maze[i][j]);
89 if(i*j&&i!=n-1&&j!=n-1){
90 s.maze[i][j]=maze[i][j];
91 }
92 }
93 }
94 if(n<=2){
95 puts("");
96 continue;
97 }
98 memset(dis,0x7f,sizeof(dis));
99 for(int i=0;i<n;i++){
100 if(maze[0][i]) bfs(0,i);
101 if(maze[n-1][i]) bfs(n-1,i);
102 if(maze[i][0]) bfs(i,0);
103 if(maze[i][n-1]) bfs(i,n-1);
104 }
105
106 deep=0;
107 while(true){
108 if(dfs(0,s)) break;
109 deep++;
110 }
111
112 if(flag) puts(""); flag=true;
113 for(int i=0;i<deep;i++){
114 if(ans[i]==0) puts("east");
115 elseif(ans[i]==1) puts("north");
116 elseif(ans[i]==2) puts("south");
117 elseif(ans[i]==3) puts("west");
118 }
119 }
120 }

  

HDU 2918 Tobo or not Tobo

这题步数最多只有9步,果断IDA*,因为每步会改变四个数字的曼哈顿距离,所以h()构造为 (曼哈顿距离和+3)/4,提交竟然居首了
这题也可以用广搜预处理来写,广搜九层,然后询问时直接输出就好了,也可以0ms,但内存肯定要比IDA*大
View Code
  1 #include<cstdio>
2 #include<cstring>
3 usingnamespace std;
4
5 char maze[5][5];
6 void cvrAc(){
7 char tmp=maze[0][0];
8 maze[0][0]=maze[1][0];
9 maze[1][0]=maze[1][1];
10 maze[1][1]=maze[0][1];
11 maze[0][1]=tmp;
12 }
13
14 void cvrAr(){
15 char tmp=maze[0][0];
16 maze[0][0]=maze[0][1];
17 maze[0][1]=maze[1][1];
18 maze[1][1]=maze[1][0];
19 maze[1][0]=tmp;
20 }
21
22 void cvrBc(){
23 char tmp=maze[0][1];
24 maze[0][1]=maze[1][1];
25 maze[1][1]=maze[1][2];
26 maze[1][2]=maze[0][2];
27 maze[0][2]=tmp;
28 }
29
30 void cvrBr(){
31 char tmp=maze[0][1];
32 maze[0][1]=maze[0][2];
33 maze[0][2]=maze[1][2];
34 maze[1][2]=maze[1][1];
35 maze[1][1]=tmp;
36 }
37
38 void cvrCc(){
39 char tmp=maze[1][0];
40 maze[1][0]=maze[2][0];
41 maze[2][0]=maze[2][1];
42 maze[2][1]=maze[1][1];
43 maze[1][1]=tmp;
44 }
45
46 void cvrCr(){
47 char tmp=maze[1][0];
48 maze[1][0]=maze[1][1];
49 maze[1][1]=maze[2][1];
50 maze[2][1]=maze[2][0];
51 maze[2][0]=tmp;
52 }
53
54 void cvrDc(){
55 char tmp=maze[1][1];
56 maze[1][1]=maze[2][1];
57 maze[2][1]=maze[2][2];
58 maze[2][2]=maze[1][2];
59 maze[1][2]=tmp;
60 }
61
62 void cvrDr(){
63 char tmp=maze[1][1];
64 maze[1][1]=maze[1][2];
65 maze[1][2]=maze[2][2];
66 maze[2][2]=maze[2][1];
67 maze[2][1]=tmp;
68 }
69
70 constint pos[][2]={{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
71 inline int ABS(int x){
72 if(x<0) return-x;
73 elsereturn x;
74 }
75 int h(){
76 int val=0;
77 for(int i=0;i<3;i++){
78 for(int j=0;j<3;j++){
79 int c=maze[i][j]-'1';
80 val+=ABS(pos[c][0]-i)+ABS(pos[c][1]-j);
81 }
82 }
83 return val;
84 }
85
86
87 int deep;
88 bool dfs(int d){
89 if(h()==0) returntrue;
90 if((h()+3)/4+d>deep) returnfalse;
91 cvrAc();
92 if(dfs(d+1)) returntrue;
93 cvrAr();
94 cvrAr();
95 if(dfs(d+1)) returntrue;
96 cvrAc();
97
98 cvrBc();
99 if(dfs(d+1)) returntrue;
100 cvrBr();
101 cvrBr();
102 if(dfs(d+1)) returntrue;
103 cvrBc();
104
105 cvrCc();
106 if(dfs(d+1)) returntrue;
107 cvrCr();
108 cvrCr();
109 if(dfs(d+1)) returntrue;
110 cvrCc();
111
112 cvrDc();
113 if(dfs(d+1)) returntrue;
114 cvrDr();
115 cvrDr();
116 if(dfs(d+1)) returntrue;
117 cvrDc();
118
119 returnfalse;
120 }
121
122 char str[12];
123 int main(){
124 int cas=0;
125 while(~scanf("%s",str),strcmp(str,"0000000000")){
126 int mmax=str[0]-'0';
127 int p=1;
128 for(int i=0;i<3;i++){
129 for(int j=0;j<3;j++){
130 maze[i][j]=str[p++];
131 }
132 }
133 deep=0;
134 bool flag=false;
135 while(deep<=mmax){
136 if(dfs(0)){
137 flag=true;
138 break;
139 }
140 deep++;
141 }
142 printf("%d. ",++cas);
143 if(flag) printf("%d\n",deep);
144 else puts("-1");
145 }
146 }

  

HDU 3459 Rubik 2×2×2

这题是ReDow推荐的一道好玩的题目(ReDow大神无压力的占据着第一的位置),用IDA*写,很容易想到一个很不给力的A*剪枝:因为有一块始终不会改变,可以确定3个面的颜色,根据这3个面的颜色又可以确定另外3个面的颜色,也就是说最终状态是确定的,这样可以在递归到最后3层时稍微起到点作用。跑sample都很吃力(这题都不要求是最优解,sample 20+步,而最优的16层就出结果了,还以为写错了,查代码查了半天- -),无意中提交了一下,sample都要卡一下下的代码竟然过了,200+ms。然后测了下不加A*的代码,跑了2s,看来这个A*还是很给力的

View Code
  1 #include<cstdio>
2 #include<cstring>
3 usingnamespace std;
4
5 char maze[10][10];
6 void cvrX(){
7 char tmp;
8 tmp=maze[0][3]; maze[0][3]=maze[3][6];
9 maze[3][6]=maze[4][3]; maze[4][3]=maze[2][3]; maze[2][3]=tmp;
10 tmp=maze[1][3]; maze[1][3]=maze[2][6];
11 maze[2][6]=maze[5][3]; maze[5][3]=maze[3][3]; maze[3][3]=tmp;
12 tmp=maze[2][4]; maze[2][4]=maze[2][5];
13 maze[2][5]=maze[3][5]; maze[3][5]=maze[3][4]; maze[3][4]=tmp;
14 }
15
16 void cvrY(){
17 char tmp;
18 tmp=maze[2][0]; maze[2][0]=maze[2][6];
19 maze[2][6]=maze[2][4]; maze[2][4]=maze[2][2]; maze[2][2]=tmp;
20 tmp=maze[2][1]; maze[2][1]=maze[2][7];
21 maze[2][7]=maze[2][5]; maze[2][5]=maze[2][3]; maze[2][3]=tmp;
22 tmp=maze[0][2]; maze[0][2]=maze[0][3];
23 maze[0][3]=maze[1][3]; maze[1][3]=maze[1][2]; maze[1][2]=tmp;
24 }
25
26 void cvrZ(){
27 char tmp;
28 tmp=maze[2][1]; maze[2][1]=maze[1][3];
29 maze[1][3]=maze[3][4]; maze[3][4]=maze[4][2]; maze[4][2]=tmp;
30 tmp=maze[3][1]; maze[3][1]=maze[1][2];
31 maze[1][2]=maze[2][4]; maze[2][4]=maze[4][3]; maze[4][3]=tmp;
32 tmp=maze[2][2]; maze[2][2]=maze[2][3];
33 maze[2][3]=maze[3][3]; maze[3][3]=maze[3][2]; maze[3][2]=tmp;
34 }
35
36 bool check(){
37 if(maze[0][3]!=maze[0][2]) returnfalse;
38 if(maze[1][2]!=maze[0][2]) returnfalse;
39 if(maze[1][3]!=maze[0][2]) returnfalse;
40
41 if(maze[2][1]!=maze[2][0]) returnfalse;
42 if(maze[3][0]!=maze[2][0]) returnfalse;
43 if(maze[3][1]!=maze[2][0]) returnfalse;
44
45 if(maze[2][3]!=maze[2][2]) returnfalse;
46 if(maze[3][2]!=maze[2][2]) returnfalse;
47 if(maze[3][3]!=maze[2][2]) returnfalse;
48
49 if(maze[2][5]!=maze[2][4]) returnfalse;
50 if(maze[3][4]!=maze[2][4]) returnfalse;
51 if(maze[3][5]!=maze[2][4]) returnfalse;
52
53 if(maze[2][7]!=maze[2][6]) returnfalse;
54 if(maze[3][6]!=maze[2][6]) returnfalse;
55 if(maze[3][7]!=maze[2][6]) returnfalse;
56
57 if(maze[4][3]!=maze[4][2]) returnfalse;
58 if(maze[5][2]!=maze[4][2]) returnfalse;
59 if(maze[5][3]!=maze[4][2]) returnfalse;
60 returntrue;
61 }
62
63 int h(){
64 int cnt=0;
65 if(maze[5][3]!=maze[5][2]||maze[3][6]!=maze[3][7]) cnt++;
66 if(maze[2][7]!=maze[3][7]||maze[2][0]!=maze[3][0]) cnt++;
67 if(maze[3][0]!=maze[3][1]||maze[4][2]!=maze[5][2]) cnt++;
68 return cnt;
69 }
70
71 int deep;
72 char ans[100];
73 bool dfs(int d){
74 if(deep-d<=3&&d+h()>deep) returnfalse;
75 if(d==deep) return check();
76
77 cvrX();
78 ans[d]='X';
79 if(dfs(d+1)) returntrue;
80 cvrX(); cvrX(); cvrX();
81
82 cvrY();
83 ans[d]='Y';
84 if(dfs(d+1)) returntrue;
85 cvrY(); cvrY(); cvrY();
86
87 cvrZ();
88 ans[d]='Z';
89 if(dfs(d+1)) returntrue;
90 cvrZ(); cvrZ(); cvrZ();
91
92 returnfalse;
93 }
94
95 int main(){
96 while(true){
97 for(int i=0;i<6;i++){
98 scanf("%s",maze[i]);
99 }
100 if(maze[0][2]=='.') break;
101 deep=0;
102 while(true){
103 if(dfs(0)) break;
104 deep++;
105 }
106 for(int i=0;i<deep;i++) putchar(ans[i]);
107 puts("");
108 }
109 }

  

A*、IDA*的也就这些了,别的一些搜索题目~

    

HDU 1401 Solitaire

一道经典的双广题目,去年暑假废了好大功夫写了一个很挫的200+ms的代码,今年再写就得心应手许多:
记录排序后的四个点的坐标作为当前状态,即8个小于8的数,用二进制(或者说是八进制)进行状态压缩,有近2kw种状态,用bitset进行hash,15ms过掉
View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<bitset>
4 #include<queue>
5 #include<algorithm>
6 usingnamespace std;
7
8 bitset<20000010> vis[2];
9 struct MAZE{
10 int maze[4][2];
11
12 MAZE(){}
13 MAZE(int m){
14 for(int i=0;i<4;i++){
15 for(int j=0;j<2;j++){
16 maze[i][j]=m&7;
17 m>>=3;
18 }
19 }
20 }
21
22 unsigned zip(){
23 unsigned ans=0,tmp[4];
24 for(int i=0;i<4;i++) tmp[i]=(maze[i][1]<<3)+maze[i][0];
25 sort(tmp,tmp+4);
26 for(int i=0;i<4;i++){ans<<=6;ans+=tmp[i];}
27 return ans;
28 }
29 }s,t;
30
31 queue<unsigned> qs,qt;
32 int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
33 bool flag;
34 void bfs(queue<unsigned>& que,int d){
35 int size=que.size();
36 while(size--){
37 int u=que.front(); que.pop();
38 MAZE mu(u);
39 for(int i=0;i<4;i++){
40 for(int j=0;j<4;j++){
41 MAZE mv(mu);
42 mv.maze[i][0]+=dir[j][0];
43 mv.maze[i][1]+=dir[j][1];
44 if(mv.maze[i][0]<0||mv.maze[i][1]<0) continue;
45 if(mv.maze[i][0]>=8||mv.maze[i][1]>=8) continue;
46 bool can=true;
47 for(int ii=0;ii<4;ii++){
48 if(ii==i) continue;
49 if(mv.maze[i][0]==mv.maze[ii][0]&&mv.maze[i][1]==mv.maze[ii][1]){
50 mv.maze[i][0]+=dir[j][0];
51 mv.maze[i][1]+=dir[j][1];
52 if(mv.maze[i][0]<0||mv.maze[i][1]<0){can=false;break;}
53 if(mv.maze[i][0]>=8||mv.maze[i][1]>=8){can=true;break;}
54 for(int jj=0;jj<4;jj++){
55 if(jj==i) continue;
56 if(mv.maze[i][0]==mv.maze[jj][0]&&mv.maze[i][1]==mv.maze[jj][1]){
57 can=false; break;
58 }
59 }
60 }
61 }
62 if(can){
63 int hv=mv.zip();
64 if(vis[d][hv]) continue;
65 if(vis[d^1][hv]){flag=true;return;}
66 vis[d][hv]=true;
67 que.push(hv);
68 }
69 }
70 }
71 }
72 }
73
74 int main(){
75 while(~scanf("%d%d",&s.maze[0][0],&s.maze[0][1])){
76 s.maze[0][0]-=1; s.maze[0][1]-=1;
77 while(!qs.empty()) qs.pop();
78 while(!qt.empty()) qt.pop();
79 for(int i=1;i<4;i++){
80 scanf("%d%d",&s.maze[i][0],&s.maze[i][1]);
81 s.maze[i][0]-=1; s.maze[i][1]-=1;
82 }
83 for(int i=0;i<4;i++){
84 scanf("%d%d",&t.maze[i][0],&t.maze[i][1]);
85 t.maze[i][0]-=1; t.maze[i][1]-=1;
86 }
87
88 int szip=s.zip();
89 int tzip=t.zip();
90 qs.push(szip);
91 qt.push(tzip);
92 if(szip==tzip){
93 puts("YES");
94 continue;
95 }
96 vis[0].reset();
97 vis[1].reset();
98 vis[0][szip]=1;
99 vis[1][tzip]=1;
100 flag=false;
101 int cnt=8;
102 while(cnt--){
103 if(qs.size()<=qt.size()) bfs(qs,0);
104 else bfs(qt,1);
105 if(flag) break;
106 }
107 puts(flag?"YES":"NO");
108 }
109 }

  

HDU 1430  魔板

数据量很大的一道题,双广要跑2s+而且还要记录路径,代码过烦了,参考hh博客知道预处理的方法:
由于只是8种颜色,所以标号就无所谓了,对起始状态重新修改标号为 12345678(别的也行),对目标状态标号做相应的修改,先预处理出12345678到所有状态的路径,记录所有状态的pre值,直接输出即可;其实以目标状态为标准去修改起始状态标号可以省去逆序输出路径的麻烦
View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 #include<algorithm>
5 usingnamespace std;
6
7 char smaze[10],tmaze[10];
8 bool vis[50000];
9 constint fac[]={1,1,2,6,24,120,720,5040,40320};
10 int inv_hash(char str[]){
11 int ans=0;
12 for(int i=0;i<8;i++){
13 int cnt=0;
14 for(int k=i-1;k>=0;k--){
15 if(str[k]>str[i]) cnt++;
16 }
17 ans+=fac[i]*cnt;
18 }
19 return ans;
20 }
21
22 struct Node{
23 char str[10];
24 Node(){}
25 Node(char _s[]){
26 for(int i=0;i<8;i++){
27 str[i]=_s[i];
28 }
29 }
30 };
31
32 void cvrA(Node& n){
33 reverse(n.str,n.str+8);
34 }
35
36 void cvrB(Node& n){
37 char tmp;
38 tmp=n.str[0]; n.str[0]=n.str[3]; n.str[3]=n.str[2];
39 n.str[2]=n.str[1]; n.str[1]=tmp;
40 tmp=n.str[4]; n.str[4]=n.str[5]; n.str[5]=n.str[6];
41 n.str[6]=n.str[7]; n.str[7]=tmp;
42 }
43
44 void cvrC(Node& n){
45 char tmp=n.str[1]; n.str[1]=n.str[6]; n.str[6]=n.str[5];
46 n.str[5]=n.str[2]; n.str[2]=tmp;
47 }
48
49 int pre[50000];
50 char ctrl[50000];
51 void bfs(){
52 memset(vis,false,sizeof(vis));
53 queue<Node> que;
54 que.push(Node("12345678"));
55 vis[0]=true;
56 while(!que.empty()){
57 Node u=que.front(); que.pop();
58 int uh=inv_hash(u.str);
59 Node v(u);
60 cvrA(v);
61 int vh=inv_hash(v.str);
62 if(!vis[vh]){
63 vis[vh]=true;
64 pre[vh]=uh;
65 ctrl[vh]='A';
66 que.push(v);
67 }
68
69 v=u;
70 cvrB(v);
71 vh=inv_hash(v.str);
72 if(!vis[vh]){
73 vis[vh]=true;
74 pre[vh]=uh;
75 ctrl[vh]='B';
76 que.push(v);
77 }
78
79 v=u;
80 cvrC(v);
81 vh=inv_hash(v.str);
82 if(!vis[vh]){
83 vis[vh]=true;
84 pre[vh]=uh;
85 ctrl[vh]='C';
86 que.push(v);
87 }
88 }
89 }
90
91 char stk[1000];
92 int pmaze[10];
93 int main(){
94 bfs();
95 while(~scanf("%s %s",smaze,tmaze)){
96 for(int i=0;i<8;i++) pmaze[smaze[i]-'1']=i;
97 for(int i=0;i<8;i++) tmaze[i]=pmaze[tmaze[i]-'1']+'1';
98 Node tN=Node(tmaze);
99 int tmp=inv_hash(tN.str);
100 int t=0;
101 while(tmp){
102 stk[t++]=ctrl[tmp];
103 tmp=pre[tmp];
104 }
105 while(t--) putchar(stk[t]);
106 puts("");
107 }
108 }

  

HDU 3567 Eight II

Eight 的加强版

做过魔板这题再做这题,脑子里就只有预处理的方法了,因为这题有一个特殊的点X,所以枚举X的位置,打出9张前驱表,用魔板题一样的方法将两个状态的对应标号转化,输出就好了,800ms

View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 usingnamespace std;
5
6 struct S{
7 char maze[3][3];
8 int x,y;
9
10 S(){}
11 S(constchar*str){
12 for(int i=0,tx=0,ty=0;str[i];i++){
13 maze[tx][ty]=str[i];
14 if(str[i]=='X'){x=tx;y=ty;}
15 ty++;if(ty==3){ty=0;tx++;}
16 }
17 }
18 };
19 int pre[10][363000];
20 char op[10][363000];
21
22 constint fac[]={1,1,2,6,24,120,720,5040,40320};
23 bool vis[363000];
24 inline int inv_hash(S ts){
25 char str[10]; int ans=0;
26 for(int i=0;i<3;i++){
27 for(int j=0;j<3;j++){
28 str[i*3+j]=ts.maze[i][j];
29 int cnt=0;
30 for(int k=i*3+j-1;k>=0;k--){
31 if(str[k]>str[i*3+j]) cnt++;
32 }
33 ans+=fac[i*3+j]*cnt;
34 }
35 }
36 return ans;
37 }
38
39 S s;
40 constint dir[4][2]={{1,0},{0,-1},{0,1},{-1,0}};
41 constchar cdir[]="dlru";
42 void bfs(int x){
43 memset(pre[x],-1,sizeof(pre[x]));
44 memset(vis,false,sizeof(vis));
45
46 queue<S> que;
47 que.push(s);
48 vis[inv_hash(s)]=true;
49 while(!que.empty()){
50 S u=que.front(); que.pop();
51 int ihu=inv_hash(u);
52 for(int i=0;i<4;i++){
53 S v=u;
54 v.x+=dir[i][0];
55 v.y+=dir[i][1];
56 if(v.x<0||v.y<0||v.x>=3||v.y>=3) continue;
57 v.maze[u.x][u.y]=v.maze[v.x][v.y];
58 v.maze[v.x][v.y]='X';
59 int ihv=inv_hash(v);
60 if(vis[ihv]) continue;
61 vis[ihv]=true;
62 pre[x][ihv]=ihu;
63 op[x][ihv]=cdir[i];
64 que.push(v);
65 }
66 }
67 }
68
69 charin[100];
70 char stk[100];
71 int cvr[10];
72 int main(){
73 s=S("X12345678"); bfs(0);
74 s=S("1X2345678"); bfs(1);
75 s=S("12X345678"); bfs(2);
76 s=S("123X45678"); bfs(3);
77 s=S("1234X5678"); bfs(4);
78 s=S("12345X678"); bfs(5);
79 s=S("123456X78"); bfs(6);
80 s=S("1234567X8"); bfs(7);
81 s=S("12345678X"); bfs(8);
82
83 int t,cas=0;
84 scanf("%d",&t);
85 while(t--){
86 int p;
87 scanf("%s",in);
88 for(int i=0,j=0;in[i];i++){
89 if(in[i]!='X') cvr[in[i]-'0']=j++;
90 else p=i;
91 }
92 scanf("%s",in);
93 for(int i=0;in[i];i++){
94 if(in[i]=='X') continue;
95 in[i]=cvr[in[i]-'0']+'1';
96 }
97 s=S(in);
98 int ihs=inv_hash(s);
99 int top=-1,tmp=ihs;
100 while(tmp!=-1){
101 stk[++top]=op[p][tmp];
102 tmp=pre[p][tmp];
103 }
104 printf("Case %d: %d\n",++cas,top);
105 while((--top)!=-1){
106 putchar(stk[top]);
107 }
108 puts("");
109 }
110 }

  

HDU 2691 2-Dimensional Rubik's Cube

这题是3459的加强版,双广,状态太多了,试了几种字符串hash都有冲突,sample都出不来,只好改用map,跑了3s+,后来问了hh,因为只有六种颜色,可以将每种状态转换成一个long long型,6^24,可以用散列表hash,改成散列表之后瞬间快很多,600+ms

View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 #include<map>
5 usingnamespace std;
6 #define LL long long
7
8 int ctoi[128];
9 struct S{
10 char maze[25];
11
12 LL zip(){
13 LL res=0;
14 for(int i=0;i<24;i++){
15 res*=6;
16 res+=ctoi[maze[i]];
17 }
18 return res;
19 }
20 }s[2];
21 LL vis[2][2000007];
22 queue<S> que[2];
23
24 int cvr[12][12]={
25 {4,12,13,5,11,22,14,2,19,20,6,0},
26 {12,13,5,4,22,14,2,11,20,6,0,19},
27 {6,14,15,7,5,20,16,3,13,21,8,2},
28 {14,15,7,6,20,16,3,5,21,8,2,13},
29 {8,16,17,9,7,21,18,1,15,23,10,3},
30 {16,17,9,8,21,18,1,7,23,10,3,15},
31 {10,18,19,11,9,23,12,0,17,22,4,1},
32 {18,19,11,10,23,12,0,9,22,4,1,17},
33 {0,2,3,1,4,6,8,10,5,7,9,11},
34 {2,3,1,0,6,8,10,4,7,9,11,5},
35 {20,22,23,21,13,19,17,15,12,18,16,14},
36 {22,23,21,20,19,17,15,13,18,16,14,12}};
37
38 /*
39 0 1
40 2 3
41 4 5 6 7 8 9 10 11
42 12 13 14 15 16 17 18 19
43 20 21
44 22 23
45 */
46
47 inline int _hash(LL _h,int x){
48 int p=_h%2000007,cnt=0;
49 while(true){
50 if(vis[x][p]==-1) return p;
51 if(vis[x][p]!=-1&&vis[x][p]==_h) return p;
52 p++; if(p>=2000007) p=0;
53 }
54 return-1;
55 }
56
57 bool flag;
58 char tmp[25];
59 void bfs(int x){
60 int size=que[x].size();
61 while(size--){
62 S u=que[x].front(); que[x].pop();
63
64 memcpy(tmp,u.maze,sizeof(u.maze));
65 for(int i=0;i<12;i++){
66 S v(u);
67 for(int j=0;j<12;j++) v.maze[cvr[i][j]]=tmp[cvr[i^1][j]];
68 LL vz=v.zip();
69 int px=_hash(vz,x),_px=_hash(vz,x^1);
70 if(~vis[x][px]) continue;
71 if(~vis[x^1][_px]){flag=true;return;}
72 vis[x][px]=vz;
73 que[x].push(v);
74 }
75 }
76 }
77
78 voidin(char&in){
79 char c=getchar();
80 while(c<=32) c=getchar();
81 in=c;
82 }
83
84 int dbfs(){
85 while(!que[0].empty()) que[0].pop();
86 while(!que[1].empty()) que[1].pop();
87 memset(vis,-1,sizeof(vis));
88 que[0].push(s[0]);
89 que[1].push(s[1]);
90 LL s0z=s[0].zip(),s1z=s[1].zip();
91 vis[0][_hash(s0z,0)]=s0z;
92 if(~vis[0][_hash(s1z,0)]) return0;
93 vis[1][_hash(s1z,1)]=s1z;
94 flag=false;
95 int cnt=0;
96 while(true){
97 cnt++;
98 if(que[0].size()<que[1].size()) bfs(0);
99 else bfs(1);
100 if(flag) break;
101 }
102 return cnt;
103 }
104
105 int main(){
106 ctoi['G']=0;
107 ctoi['W']=1;
108 ctoi['Y']=2;
109 ctoi['O']=3;
110 ctoi['R']=4;
111 ctoi['B']=5;
112
113 int t;
114 scanf("%d",&t);
115 while(t--){
116 for(int i=0;i<24;i++) in(s[0].maze[i]);
117 for(int i=0;i<24;i++) in(s[1].maze[i]);
118 int ans=dbfs();
119 printf("%d\n",ans);
120 }
121 }

  

HDU 3278 Puzzle

在hh博客看到的一个月赛题目,虽然做之前就知道IDA*过不了,但还是想敲一下,毕竟码短、简单,结果不料WA到死,一直找不到错,只好改方法;这题看起来跟1667题相似,但那题每次只会产生8种状态,这题有20种,普通的方法很难AC,G了一下原来可以预处理:假定W是最终在中间位置的颜色,那么就把G和B当作同一种颜色,这样就可以通过二进制压缩把状态用一个整形数字表示,预处理出所有状态之后取三种颜色的最小值即可,2kw的数组开起来确实很吃力,使用char型终于水过了这题~~(后来看下后台,竟然有十万组数据,搞毛啊,害我IDA*狂交还报WA T_T)

View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 usingnamespace std;
5
6 struct S{
7 bool maze[5][8];
8 S(unsigned _v){
9 for(int i=3;i>=0;i--){
10 for(int j=5;j>=0;j--){
11 maze[i][j]=_v&1; _v>>=1;
12 }
13 }
14 }
15 unsigned zip(){
16 unsigned res=0;
17 for(int i=0;i<4;i++){
18 for(int j=0;j<6;j++){
19 res<<=1;
20 res|=maze[i][j];
21 }
22 }
23 return res;
24 }
25 };
26
27 struct SS{
28 int val,s;
29 SS(){}
30 SS(int _v,int _s)
31 :val(_v),s(_s){}
32 };
33
34 inline void roU(S& t,int x){
35 bool tmp=t.maze[0][x];
36 t.maze[0][x]=t.maze[1][x];
37 t.maze[1][x]=t.maze[2][x];
38 t.maze[2][x]=t.maze[3][x];
39 t.maze[3][x]=tmp;
40 }
41
42 inline void roD(S& t,int x){
43 bool tmp=t.maze[0][x];
44 t.maze[0][x]=t.maze[3][x];
45 t.maze[3][x]=t.maze[2][x];
46 t.maze[2][x]=t.maze[1][x];
47 t.maze[1][x]=tmp;
48 }
49
50 inline void roL(S& t,int x){
51 bool tmp=t.maze[x][0];
52 t.maze[x][0]=t.maze[x][1];
53 t.maze[x][1]=t.maze[x][2];
54 t.maze[x][2]=t.maze[x][3];
55 t.maze[x][3]=t.maze[x][4];
56 t.maze[x][4]=t.maze[x][5];
57 t.maze[x][5]=tmp;
58 }
59
60 inline void roR(S& t,int x){
61 bool tmp=t.maze[x][0];
62 t.maze[x][0]=t.maze[x][5];
63 t.maze[x][5]=t.maze[x][4];
64 t.maze[x][4]=t.maze[x][3];
65 t.maze[x][3]=t.maze[x][2];
66 t.maze[x][2]=t.maze[x][1];
67 t.maze[x][1]=tmp;
68 }
69
70 char step[1<<24];
71 void bfs(){
72 queue<SS> que;
73 que.push(SS(124800,0));
74 step[124800]=-1;
75
76 while(!que.empty()){
77 SS u=que.front(); que.pop();
78 u.s+=1;
79
80 for(int i=0;i<4;i++){
81 S v(u.val);
82 roL(v,i);
83 unsigned _zip=v.zip();
84 if(!step[_zip]){
85 step[_zip]=u.s;
86 que.push(SS(_zip,u.s));
87 }
88 roR(v,i); roR(v,i);
89 _zip=v.zip();
90 if(!step[_zip]){
91 step[_zip]=u.s;
92 que.push(SS(_zip,u.s));
93 }
94 }
95 for(int i=0;i<6;i++){
96 S v(u.val);
97 roU(v,i);
98 int _zip=v.zip();
99 if(!step[_zip]){
100 step[_zip]=u.s;
101 que.push(SS(_zip,u.s));
102 }
103 roD(v,i); roD(v,i);
104 _zip=v.zip();
105 if(!step[_zip]){
106 step[_zip]=u.s;
107 que.push(SS(_zip,u.s));
108 }
109 }
110 }
111 }
112
113 char maze[5][8];
114 char code[]="WGB";
115 int main(){
116 bfs();
117 int t,cas=0;
118 scanf("%d",&t);
119 while(t--){
120 for(int i=0;i<4;i++){
121 scanf("%s",maze[i]);
122 }
123 int ans=100000;
124 for(int i=0;i<3;i++){
125 unsigned _zip=0;
126 for(int ii=0;ii<4;ii++){
127 for(int jj=0;jj<6;jj++){
128 _zip<<=1;
129 if(maze[ii][jj]==code[i]){
130 _zip|=1;
131 }
132 }
133 }
134 if(_zip==124800){ans=0;break;}
135 if(ans>step[_zip]) ans=step[_zip];
136 }
137 printf("Case %d: %d\n",++cas,ans);
138 }
139 }

    

 

(2011/8/21)

ZOJ 2477 Magic Cube

三阶魔方旋转,因为最多5层,IDA*,因为每个面中间的位置是不变的构造h()为 (MAX(每个面周围的八个字符与中间字符不同的个数)+2)/3,然后暴搜就行了,话说转换数组确实好用,代码量少了几倍,0ms榜首

View Code
 1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<cstdlib>
5 usingnamespace std;
6
7 voidin(char&c){
8 c=getchar();
9 while(c<=32) c=getchar();
10 }
11
12 char s[60];
13 int cvr[12][20]={
14 {11,23,35,34,33,21,9,10,51,48,45,36,24,12,6,3,0,20,32,44},
15 {9,10,11,23,35,34,33,21,36,24,12,6,3,0,20,32,44,51,48,45},
16 {14,13,26,38,37,36,24,12,45,46,47,39,27,15,8,7,6,11,23,35},
17 {12,24,13,14,26,38,37,36,39,27,15,8,7,6,11,23,35,45,46,47},
18 {17,29,41,40,39,27,15,16,47,50,53,42,30,18,2,5,8,14,26,38},
19 {15,16,17,29,41,40,39,27,42,30,18,2,5,8,14,26,38,47,50,53},
20 {18,19,20,32,44,43,42,30,53,52,51,33,21,9,0,1,2,17,29,41},
21 {42,30,18,19,20,32,44,43,33,21,9,0,1,2,17,29,41,53,52,51},
22 {0,1,2,5,8,7,6,3,12,13,14,15,16,17,18,19,20,9,10,11},
23 {6,3,0,1,2,5,8,7,15,16,17,18,19,20,9,10,11,12,13,14},
24 {45,46,47,50,53,52,51,48,44,43,42,41,40,39,38,37,36,35,34,33},
25 {51,48,45,46,47,50,53,52,41,40,39,38,37,36,35,34,33,44,43,42}};
26
27 int cent[6]={22,25,28,31,4,49};
28 int h(){
29 int cnt=0;
30 for(int i=0;i<6;i++){
31 int tmp=0;
32 for(int j=0;j<8;j++){
33 if(s[cvr[i<<1][j]]!=s[cent[i]]){
34 tmp++;
35 }
36 }
37 if(tmp>cnt) cnt=tmp;
38 }
39 return cnt;
40 }
41
42 int deep;
43 int ans[10];
44
45 bool dfs(int k){
46 if(k==deep) return h()==0;
47 if(k+(h()+2)/3>deep) returnfalse;
48
49 char tmp[60];
50 for(int i=0;i<12;i++){
51 memcpy(tmp,s,sizeof(s));
52 for(int j=0;j<20;j++) s[cvr[i][j]]=tmp[cvr[i^1][j]];
53 ans[k]=i;
54 if(dfs(k+1)) returntrue;
55 memcpy(s,tmp,sizeof(s));
56 }
57 returnfalse;
58 }
59
60
61 int main(){
62 int t;
63 scanf("%d",&t);
64 while(t--){
65 for(int i=0;i<54;i++){
66 in(s[i]);
67 }
68
69 deep=0;
70 while(true){
71 if(dfs(0)) break;
72 deep++;
73 if(deep>5) break;
74 }
75
76 if(deep>5) puts("-1");
77 else{
78 printf("%d\n",deep);
79 for(int i=0;i<deep;i++){
80 printf("%d %d\n",ans[i]>>1,(ans[i]%2)?-1:1);
81 }
82 }
83 }
84 }

  

(2011/8/25)

HDU 2953 Rubiks Cube

题解这里

  

HDU 3121 FreeOpen

题解这里

  

(2011/9/8)

HDU 4012 Paint on a Wall

题解这里

  

另外补两道以前做的几道题的题解:

HDU 3900 Unblock me

比赛时候一直搞这题,最终导致全队悲剧 - -

开始时用IDA*去做,结果sample跑了十分钟都没出,题目中的条件好多没用上,想不出方法来,后来看了题解,太佩服这题出题人了,状态压缩用到了极致的神题

因为只有1*2,1*3,2*1,3*1几种块,又有水平条只能水平移竖直条只能竖直移,那么就可以看出每块的位置只有四五种情况,用八进制保存每一块的位置情况,根据静态记录的每一块的行或列算出他的实际位置,然后就是各种二进制操作了

View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 #include<map>
5 usingnamespace std;
6 #define LL long long
7
8 struct Block{
9 int t,l,c;
10 }B[20];
11
12 int n,r;
13 map<LL,bool> vis;
14
15 inline bool check(LL s,int x){
16 int tx=(s&(7LL<<(x*3)))>>(x*3);
17 for(int i=0;i<n;i++){
18 if(i==x) continue;
19 int ti=(s&(7LL<<(i*3)))>>(i*3);
20 if(B[x].t==B[i].t){
21 if(B[x].c!=B[i].c) continue;
22 if((tx+B[x].l<=ti)||(ti+B[i].l<=tx)) continue;
23 returnfalse;
24 }else{
25 if((tx+B[x].l>B[i].c)&&(tx<=B[i].c)
26 &&(ti+B[i].l>B[x].c)&&(ti<=B[x].c)) returnfalse;
27 }
28 }
29 returntrue;
30 }
31
32 inline bool done(LL s){
33 for(int i=0;i<n;i++){
34 if(B[i].t) continue;
35 if(B[i].c<((s&(7LL<<(r*3)))>>(r*3))+B[r].l) continue;
36 int l=((s&(7LL<<(i*3)))>>(i*3)),r=l+B[i].l;
37 if(r<=2||l>2) continue;
38 returnfalse;
39 }
40 returntrue;
41 }
42
43 inline void cvr(LL& s,int x,int p){
44 s&=~(7LL<<(x*3));
45 s|=(LL)p<<(x*3);
46 }
47
48 int bfs(LL s){
49 if(done(s)) return1;
50 queue<pair<LL,int>> que;
51 que.push(make_pair(s,0));
52 vis.clear();
53 vis[s]=true;
54 while(!que.empty()){
55 LL u=que.front().first;
56 int d=que.front().second+1;
57 que.pop();
58 for(int i=0;i<n;i++){
59 int p=(u&(7LL<<(i*3)))>>(i*3);
60
61 for(int j=1;p-j>=0;j++){
62 LL v=u;
63 cvr(v,i,p-j);
64 if(!check(v,i)) break;
65 if(done(v)) return d+1;
66 if(vis[v]) continue;
67 vis[v]=true;
68 que.push(make_pair(v,d));
69 }
70
71 for(int j=1;p+j+B[i].l<=6;j++){
72 LL v=u;
73 cvr(v,i,p+j);
74 if(!check(v,i)) break;
75 if(done(v)) return d+1;
76 if(vis[v]) continue;
77 vis[v]=true;
78 que.push(make_pair(v,d));
79 }
80 }
81 }
82 return-1;
83 }
84
85 int main(){
86 while(~scanf("%d",&n)){
87 LL s=0;
88 for(int i=0;i<n;i++){
89 int lx,ly,rx,ry;
90 scanf("%*d %d%d%d%d",&lx,&ly,&rx,&ry);
91 if(lx==rx){
92 B[i].t=0;
93 B[i].l=ry-ly+1;
94 B[i].c=lx;
95 s|=((LL)ly<<(3*i));
96 }else{
97 B[i].t=1;
98 B[i].l=rx-lx+1;
99 B[i].c=ly;
100 s|=((LL)lx<<(3*i));
101 }
102 }
103 scanf("%d",&r);
104
105 int ans=bfs(s);
106 printf("%d\n",ans);
107 }
108 }

  

HDU 3085 Nightmare II

二日月教主的题,开始一看到800*800就开始脑残了,去想IDA*,后来IDA*写一半发现根本不用记录状态的 = =||,这题目就一个简单的双向广搜,也有人用三广去做,恶魔可以穿墙的,所以直接根据坐标计算就好了

 

View Code
 1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 usingnamespace std;
5
6 struct S{
7 int x,y;
8 S(){}
9 S(int _x,int _y):
10 x(_x),y(_y){}
11 }bs,gs,gh[2];
12 int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
13 int lx,ly;
14 char maze[805][805];
15
16 inline int ABS(int x){
17 if(x<0) return-x;
18 return x;
19 }
20
21 inline bool check(int x,int y,int d){
22 if(x<0||y<0||x>=lx||y>=ly) returnfalse;
23 if(maze[x][y]=='X') returnfalse;
24 if(ABS(x-gh[0].x)+ABS(y-gh[0].y)<=d<<1) returnfalse;
25 if(ABS(x-gh[1].x)+ABS(y-gh[1].y)<=d<<1) returnfalse;
26 returntrue;
27 }
28
29 int dep;
30 bool flag;
31 bool vis[2][805][805];
32 queue<S> que[2];
33
34 void bfs(int t){
35 int size=que[t].size();
36 while(size--){
37 int x=que[t].front().x;
38 int y=que[t].front().y;
39 que[t].pop();
40 if(!check(x,y,dep)) continue;
41 for(int i=0;i<4;i++){
42 int tx=x+dir[i][0];
43 int ty=y+dir[i][1];
44 if(!check(tx,ty,dep)) continue;
45 if(vis[t][tx][ty]) continue;
46 if(vis[t^1][tx][ty]){flag=true;return;}
47 vis[t][tx][ty]=true;
48 que[t].push(S(tx,ty));
49 }
50 }
51 }
52
53 int dbfs(){
54 memset(vis,false,sizeof(vis));
55 while(!que[0].empty()) que[0].pop();
56 while(!que[1].empty()) que[1].pop();
57
58 que[0].push(gs);
59 que[1].push(bs);
60 vis[0][gs.x][gs.y]=true;
61 vis[1][bs.x][bs.y]=true;
62
63 flag=false;
64 dep=0;
65 while(true){
66 if(!que[0].size()) return-1;
67 if(!que[1].size()) return-1;
68 dep++;
69 bfs(0); if(flag) return dep;
70 bfs(1); if(flag) return dep;
71 bfs(1); if(flag) return dep;
72 bfs(1); if(flag) return dep;
73 }
74 }
75
76 int main(){
77 int t;
78 scanf("%d",&t);
79 while(t--){
80 scanf("%d%d",&lx,&ly);
81 for(int i=0,k=0;i<lx;i++){
82 scanf("%s",maze[i]);
83 for(int j=0;j<ly;j++){
84 if(maze[i][j]=='M') bs=S(i,j);
85 if(maze[i][j]=='G') gs=S(i,j);
86 if(maze[i][j]=='Z') gh[k++]=S(i,j);
87 }
88 }
89 int ans=dbfs();
90 printf("%d\n",ans);
91 }
92 }

 

  

HDU 3309 Roll The Cube

小丽姐的题,状态表示和转移超级恶心,因为在一半的时候会有一个球和一个洞没掉,要用另外的标记表示,代码写的很烂很烂

 

View Code
  1 #include<cstdio>
2 #include<cstring>
3 #include<bitset>
4 #include<queue>
5 usingnamespace std;
6
7 struct S{
8 int b1,b2;
9 bool h1,h2;
10 int s;
11
12 void ex(){
13 if(b1>b2){int t=b1; b1=b2; b2=t;}
14 }
15
16 int zip(){
17 int val=0;
18 val|=h1; val<<=1;
19 val|=h2; val<<=10;
20 val|=b1; val<<=10;
21 val|=b2;
22 return val;
23 }
24 }s;
25
26 int hx[3],hy[3];
27 int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
28 char maze[25][25];
29 bitset<5000000> vis;
30
31 int bfs(){
32 vis.reset();
33 vis[s.zip()]=true;
34
35 queue<S> que;
36 que.push(s);
37
38 while(!que.empty()){
39 S u=que.front(); que.pop();
40
41 int bx1=(u.b1&0x3E0)>>5;
42 int by1=u.b1&0x1F;
43 int bx2=(u.b2&0x3E0)>>5;
44 int by2=u.b2&0x1F;
45
46 //printf("(%d,%d) (%d,%d)\n",bx1,by1,bx2,by2);
47 for(int i=0;i<4;i++){
48 int tbx1=0x1F,tby1=0x1F;
49 int tbx2=0x1F,tby2=0x1F;
50 if(u.b1!=0x3FF){
51 tbx1=bx1+dir[i][0];
52 tby1=by1+dir[i][1];
53 }
54 if(u.b2!=0x3FF){
55 tbx2=bx2+dir[i][0];
56 tby2=by2+dir[i][1];
57 }
58 if((tbx1!=0x1F)&&maze[tbx1][tby1]=='*'){
59 tbx1-=dir[i][0];
60 tby1-=dir[i][1];
61 if(tbx2!=0x1F&&(tbx2==tbx1&&tby2==tby1)) continue;
62 }
63 if((tbx2!=0x1F)&&maze[tbx2][tby2]=='*'){
64 tbx2-=dir[i][0];
65 tby2-=dir[i][1];
66 if(tbx1!=0x1F&&(tbx1==tbx2&&tby1==tby2)) continue;
67 }
68 S v; v.s=u.s+1;
69 v.b1=(tbx1<<5)|tby1;
70 v.b2=(tbx2<<5)|tby2;
71 v.h1=u.h1; v.h2=u.h2;
72 if(v.h1&&tbx1==hx[0]&&tby1==hy[0]){v.b1=0x3FF;v.h1=false;}
73 if(v.h2&&tbx1==hx[1]&&tby1==hy[1]){v.b1=0x3FF;v.h2=false;}
74 if(v.h1&&tbx2==hx[0]&&tby2==hy[0]){v.b2=0x3FF;v.h1=false;}
75 if(v.h2&&tbx2==hx[1]&&tby2==hy[1]){v.b2=0x3FF;v.h2=false;}
76
77 v.ex();
78 if((!v.h1)&&(!v.h2)) return v.s;
79 int _h=v.zip();
80 //printf("- %d %d %d\n",v.b1,v.b2,_h);
81 if(vis[_h]) continue;
82 vis[_h]=true;
83 que.push(v);
84 }
85 }
86 return-1;
87 }
88
89 int main(){
90 int t;
91 scanf("%d",&t);
92 while(t--){
93 int lx,ly;
94 scanf("%d%d",&lx,&ly);
95 for(int i=0,b=0,h=0;i<lx;i++){
96 scanf("%s",maze[i]);
97 for(int j=0;j<ly;j++){
98 if(maze[i][j]=='B'){
99 if(!b) s.b1=(i<<5)|j;
100 else s.b2=(i<<5)|j;
101 b++; maze[i][j]='.';
102 }
103 if(maze[i][j]=='H'){
104 hx[h]=i;
105 hy[h]=j;
106 h++;
107 maze[i][j]='.';
108 }
109 }
110 }
111 s.h1=true; s.h2=true;
112 s.ex(); s.s=0;
113 int ans=bfs();
114 if(ans!=-1){
115 printf("%d\n",ans);
116 }else puts("Sorry , sir , my poor program fails to get an answer.");
117 }
118 }

  

  

(2012/7)

  

UVa 12402 Parallel Missions

题解这里

 

CodeForces 83C Track

题解这里

 

转载请注明:http://www.cnblogs.com/ambition/archive/2011/07/17/2108612.html 

 

posted @ 2011-07-25 19:20  Amb@HDU  阅读(6321)  评论(13编辑  收藏  举报