hdu 6171 Admiral 双向bfs+hash

来源:互联网 发布:通讯录恢复软件 编辑:程序博客网 时间:2024/05/17 23:45


Admiral

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 153428/153428 K (Java/Others)
Total Submission(s): 206    Accepted Submission(s): 54


Problem Description
Suppose that you are an admiral of a famous naval troop. Our naval forces have got 21 battleships. There are 6 types of battleships.
First, we have got one flagship in which the admiral must be and it is denoted by number 0. Others are denoted by number from 1 to 5, each of them has 2, 3, 4, 5, 6 ships of its kind. So, we have got 21 battleships in total and we must take a giant battle against the enemy. Hence, the correct strategy of how to arrange each type of battleships is very important to us.
The shape of the battlefield is like the picture that is shown below.
To simplify the problem, we consider all battleships have the same rectangular shape.

Fortunately, we have already known the optimal state of battleships.
As you can see, the battlefield consists of 6 rows. And we have 6 types of battleship, so the optimal state is that all the battleships denoted by number i are located at the i-th row. Hence, each type of battleship corresponds to different color.
You are given the initial state of battlefield as input. You can change the state of battlefield by changing the position of flagship with adjacent battleship.
Two battleships are considered adjacent if and only if they are not in the same row and share parts of their edges. For example, if we denote the cell which is at i-th row and j-th position from the left as (i,j), then the cell (2,1) is adjacent to the cells (1,0), (1,1), (3,1), (3,2).
Your task is to change the position of the battleships minimum times so as to reach the optimal state.
Note: All the coordinates are 0-base indexed.
 

Input
The first line of input contains an integer T (1 <= T <= 10), the number of test cases. 
Each test case consists of 6 lines. The i-th line of each test case contains i integers, denoting the type of battleships at i-th row of battlefield, from left to right.
 

Output
For each test case, if you can’t reach the goal in no more than 20 moves, you must output “too difficult” in one line. Otherwise, you must output the answer in one line.
 

Sample Input
112 02 1 23 3 3 34 4 4 4 45 5 5 5 5 5
 

Sample Output
3
 

Source
2017 Multi-University Training Contest - Team 10
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  6181 6180 6179 6178 6177 
 

Statistic | Submit | Discuss | Note
题意:给你一个塔,要你弄成第一行全是0的,第二行全是1,第三行全是2,以此类推,求最小步数,每一步只能把0移动到上方、左上方、下方、右下方。

思路:现场码了半天还是得10多s才能出答案。看了题解,双向bfs。。。感觉我又被套路了。在知道起点和终点的情况下,两边同时bfs能剪掉n多的枝,这个想一下还是想得通的。所以这题就把图hash成字符串(当然你也可以hash成数,6进制不会爆LL,只不过可能写起来不好写),然后两边同时bfs其中一方找到另一方时结束。可能会觉得我的代码风格有点奇怪,因为。。有一些是我叫队友码的,留接口给我用。下面给代码:

#pragma comment(linker, "/STACK:102400000,102400000") #include<iostream>  #include<cmath>  #include<queue>  #include<cstdio>  #include<queue>  #include<algorithm>  #include<cstring>  #include<string>  #include<utility>#include<set>#include<map>#include<stack>#include<vector>#define maxn 200005#define inf  0x3f3f3f3f3f3f3f3fusing namespace std;typedef long long LL;const double eps = 1e-5;const int mod = 1e9+7;int up[] = { -1, 0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, 9, -1, 10, 11, 12, 13, 14, -1 };int upleft[] = { -1, -1, 0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, 9, -1, 10, 11, 12, 13, 14 };int down[] = { 1, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 19, -1, -1, -1, -1, -1, -1 };int downright[] = { 2, 4, 5, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, -1, -1, -1, -1, -1, -1 };map<string, int>m;string ori = "011222333344444555555";queue<string>q;int solve(string next,string now,int nextpos,int pos){if (~nextpos){swap(next[pos], next[nextpos]);next[21] = nextpos / 10 + '0';next[22] = nextpos % 10 + '0';int cnt1 = m[next];int cnt2 = m[now];if (!cnt1){m[next] = m[now] + 1;q.push(next);}else if (cnt2 >= 20 && cnt1 <= 11 || (cnt2 <= 11 && cnt1 >= 20))return cnt1 + cnt2 - 20;swap(next[pos], next[nextpos]);}return 0;}int bfs(string x){while (!q.empty())q.pop();m.clear();int index;for (int i = 0; i < 21;i++)if (x[i] == '0'){index = i;break;}char s[5];s[0] = index / 10 + '0';s[1] = index % 10 + '0';s[2] = '\0';q.push(x += s);q.push("01122233334444455555500");m[x] = 20;m["01122233334444455555500"] = 1;while (!q.empty()){string now = q.front();q.pop();int num = m[now];if (num == 11 || num == 30)continue;int pos = (now[21] - '0') * 10 + now[22] - '0';int nextpos = up[pos];string next = now;int ans = solve(next, now, nextpos, pos);if (ans)return ans;nextpos = upleft[pos];ans = solve(next, now, nextpos, pos);if (ans)return ans;nextpos = down[pos];ans = solve(next, now, nextpos, pos);if (ans)return ans;nextpos = downright[pos];ans = solve(next, now, nextpos, pos);if (ans)return ans;}return -1;}string input(){int cnt = 21;string s = "", t;while (cnt--) cin >> t, s += t;return s;}int main(){int t;scanf("%d", &t);while (t--){string now = input();if (now == ori){printf("0\n");continue;}int ans = bfs(now);if (~ans)printf("%d\n", ans);elseprintf("too difficult\n");}}