【状压+状态转移】A Famous Airport Managere
https://www.bnuoj.com/v3/problem_show.php?pid=25653
【题意】
- 给定一个3*3的九宫格,模拟一个停机坪。第一个格子一定是'*',代表take off area,其他的格子可能是'*','B','G'中的一种,'*'代表空地,'B','G'代表蓝色和绿色的飞机。
- 每次操作都是一个飞机移动到take off area并起飞,在这个过程中其他飞机不能动。
- 问有多少种飞机起飞的不同序列,同一种颜色的飞机是一模一样的。
【思路】
- 这个停机坪最多有3^8=6561中不同的状态,可以考虑用三进制状压。
- 状态之间可以转移。比如:
可以由转移来,也就是当前的出队序列就是B+pre的出队序列。
可以由转移来,也就是当前的出队序列就是G+pre的出队序列。
- 这个出队序列也可以状压,为了表示方便,我们把当前的出队序列表示为pre的出队序列后面接上B或G,这样就可以用[pre]*3+1或[pre]*3+2表示当前状态。
- 使用set可以自动去重,去掉重复的状态。
【Accepted】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 #include<set> 8 #include<queue> 9 using namespace std; 10 const int maxn=6561; 11 const int inf=0x3f3f3f3f; 12 char s[3][4]; 13 int a[10]; 14 int dig[10]; 15 set<int> dp[maxn]; 16 set<int>:: iterator it; 17 bool v[4][4]; 18 int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; 19 void init() 20 { 21 dig[0]=1; 22 for(int i=1;i<=9;i++) 23 { 24 dig[i]=dig[i-1]*3; 25 } 26 } 27 28 void BFS() 29 { 30 queue<pair<int,int> >Q; 31 memset(v,false,sizeof(v)); 32 Q.push(make_pair(0,0)); 33 v[0][0]=true; 34 while(!Q.empty()) 35 { 36 int x=Q.front().first; 37 int y=Q.front().second; 38 Q.pop(); 39 // cout<<x<<" "<<y<<endl; 40 for(int i=0;i<4;i++) 41 { 42 int xx=x+dir[i][0]; 43 int yy=y+dir[i][1]; 44 if(v[xx][yy]) 45 { 46 continue; 47 } 48 if(xx<0||x>=3||y<0||y>=3) 49 { 50 continue; 51 } 52 v[xx][yy]=true; 53 if(s[xx][yy]=='*') 54 { 55 Q.push(make_pair(xx,yy)); 56 } 57 } 58 } 59 } 60 61 void DP() 62 { 63 dp[0].insert(0); 64 for(int i=1;i<dig[8];i++) 65 { 66 int now=i; 67 for(int j=0;j<9;j++) 68 { 69 a[8-j]=now%3; 70 now/=3; 71 } 72 for(int j=0;j<3;j++) 73 { 74 for(int k=0;k<3;k++) 75 { 76 if(a[j*3+k]==0) 77 { 78 s[j][k]='*'; 79 } 80 else if(a[j*3+k]==1) 81 { 82 s[j][k]='B'; 83 } 84 else 85 { 86 s[j][k]='G'; 87 } 88 } 89 } 90 BFS(); 91 for(int j=0;j<3;j++) 92 { 93 for(int k=0;k<3;k++) 94 { 95 if(v[j][k]&&s[j][k]=='B') 96 { 97 int pre=i-1*dig[8-3*j-k]; 98 for(it=dp[pre].begin();it!=dp[pre].end();it++) 99 { 100 dp[i].insert(*(it)*3+1); 101 } 102 } 103 else if(v[j][k]&&s[j][k]=='G') 104 { 105 int pre=i-2*dig[8-3*j-k]; 106 for(it=dp[pre].begin();it!=dp[pre].end();it++) 107 { 108 dp[i].insert(*(it)*3+2); 109 } 110 } 111 } 112 } 113 } 114 } 115 int main() 116 { 117 init(); 118 DP(); 119 int cas=0; 120 while(~scanf("%s%s%s",s[0],s[1],s[2])) 121 { 122 for(int i=0;i<3;i++) 123 { 124 for(int k=0;k<3;k++) 125 { 126 if(s[i][k]=='*') 127 { 128 a[3*i+k]=0; 129 } 130 else if(s[i][k]=='B') 131 { 132 a[3*i+k]=1; 133 } 134 else 135 { 136 a[3*i+k]=2; 137 } 138 } 139 } 140 int now=0; 141 for(int i=0;i<9;i++) 142 { 143 now+=a[i]*dig[8-i]; 144 } 145 printf("Case %d: ",++cas); 146 cout<<dp[now].size()<<endl; 147 } 148 149 return 0; 150 }