题目大意:
就是一个3*3矩阵的游戏, 现在一共有9个格子, 然后有8个格子被8种方块填充, 另外一个是空格, 现在给出了一个表分别表示A~I位置能到达的位置和需要的代价
需要的代价只有两种
每次可以移动一个块到空位置
为从一个状态最小需要多少代价变成另外一种
大致思路:
首先对于一个当前的游戏状态,用康托展开来记录当前状态,即当前状态可以表示成a1, a2, a3, ..., a9是一个0~8的排列
那么这个状态可以映射成 a1*0! + a2*1! + .. + a9*8!
其中ai表示第i个数的前面比ai小的有几个
那么可以将所有的9!种状态映射到数字0~9! - 1
那么每个点相连的边数的4, 权值有两种
这样建好一个图之后,跑一下最短路即可
我写的spfa...貌似堆优化的dijkstra要快一点
注意建图的边要预处理, 不能每次都完全重建, 不然容易超时
代码如下:
Result : Accepted Memory : ? KB Time : 2176 ms
/* * Author: Gatevin * Created Time: 2015/10/31 13:46:57 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; int a[10]; int ch, cv; int st, ed; int fac[10]; int b[10], c[10]; #define maxn (1*2*3*4*5*6*7*8*9+10) struct Edge { int to, nex, w, typ; Edge(){} Edge(int _to, int _nex, int _w, int _typ) { to = _to, nex = _nex, w = _w, typ = _typ; } }; Edge edge[maxn*4*2 + 2]; int head[maxn]; int E; void add_Edge(int u, int v, int w, int typ) { edge[++E] = Edge(v, head[u], w, typ); head[u] = E; } int change[9][4] =//转移 { {1, 8, 6, 3}, {2, 0, 7, 4}, {3, 1, 8, 5}, {4, 2, 0, 6}, {5, 3, 1, 7}, {6, 4, 2, 8}, {7, 5, 3, 0}, {8, 6, 4, 1}, {0, 7, 5, 2} }; void build() { ch = cv = 0; memset(head, -1, sizeof(head)); E = 0; int start = 0; int end = 0; for(int i = 0; i <= 8; i++) end += i*fac[i]; for(int i = start; i <= end; i++)//解Cantor展开 { int ti = i; int emp; memset(a, 0, sizeof(a)); for(int j = 8; j >= 0; j--) { int cnt = ti / fac[j]; for(int p = 0; p <= 8; p++) { //if(a[i] == 0) cnt--; if(cnt == 0 && a[p] == 0) { b[j] = p; a[p] = 1; break; } else if(a[p] == 0) cnt--; } ti %= fac[j]; if(b[j] == 0) emp = j; } for(int k = 0; k < 4; k++)//计算目标状态的Cantor展开的值 { int swa = change[emp][k]; for(int g = 0; g <= 8; g++) c[g] = b[g]; swap(c[emp], c[swa]); int to = 0; for(int g = 0; g <= 8; g++) { int cnt = 0; for(int mabi = 0; mabi < g; mabi++) if(c[mabi] < c[g]) cnt++; to += cnt*fac[g]; } add_Edge(to, i, (k > 1) ? cv : ch, (k > 1)); } } } int Cantor() { int ret = 0; for(int i = 0; i < 9; i++) { int cnt = 0; for(int j = 0; j < i; j++) if(a[i] > a[j]) cnt++; ret += cnt*fac[i]; } return ret; } bool vis[maxn]; int dis[maxn]; const int inf = 1e9; void solve()//spfa { memset(vis, 0, sizeof(vis)); fill(dis, dis + fac[9] + 1, inf); dis[st] = 0; queue<int> Q; Q.push(st); vis[st] = 1; while(!Q.empty()) { int now = Q.front(); Q.pop(); vis[now] = 0; for(int i = head[now]; i + 1; i = edge[i].nex) { int nex = edge[i].to; if(dis[nex] > dis[now] + edge[i].w) { dis[nex] = dis[now] + edge[i].w; if(!vis[nex]) Q.push(nex), vis[nex] = 1; } } } printf("%d\n", dis[ed]); } int main() { fac[0] = fac[1] = 1; for(int i = 2; i < 10; i++) fac[i] = fac[i - 1]*i; build(); while(scanf("%d %d", &ch, &cv), ch || cv) { for(int i = 0; i < 9; i++) scanf("%d", &a[i]); st = Cantor(); for(int i = 0; i < 9; i++) scanf("%d", &a[i]); ed = Cantor(); //build(); for(int i = 1; i <= E; i++) if(edge[i].typ == 1) edge[i].w = cv; else edge[i].w = ch; solve(); } return 0; } /* 4 9 6 3 0 8 1 2 4 5 7 6 3 0 8 1 2 4 5 7 31 31 4 3 6 0 1 5 8 2 7 0 3 6 4 1 5 8 2 7 92 4 1 5 3 4 0 7 8 2 6 1 5 0 4 7 3 8 2 6 12 28 3 4 5 0 2 6 7 1 8 5 7 1 8 6 2 0 3 4 0 0 */ /* 0 31 96 312 */