标签:
时间限制:1000ms
单点时限:1000ms
内存限制:256MB
There is a strange storehouse in PKU. In this storehouse there are n slots for boxes, forming a line. In each slot you can pile up any amount of boxes. The limitation is that you can only pile a smaller one above a bigger one, in order to keep balance. The slots are numbered from 1 to n. The leftmost one is slot 1.
At first there is exactly one box in each slot. The volume of the box in slot i is vi. As a virgo, you decide to sort these boxes by moving some of them. In each move you can choose a slot and move the top box in this slot to an adjacent slot (of course you can only put it on the top). You should ensure that the limitation mentioned above is still satisfied after this move. After the sort operation, there should be exactly one box in each slot, and for each pair of adjacent slots, the box in the left one should be smaller than the box in the right one.
Your task is to calculate the minimum number of moves you need to sort the boxes.
In the first line there’s an integer T(T≤6000), indicating the number of test cases. The following 2T lines describe the test cases.
In each test case, the first line contains an integer n, indicating the number of slots. The second line contains n integers v1,v2…vn, indicating the volume of the boxes. It is guaranteed that all vi in a test case are different.
Please note that n<8,0≤vi≤104
For each test case, print a line containing one integer indicating the answer. If it’s impossible to sort the boxes, print -1.
样例输入
4
3
2 1 3
2
7 8
2
10000 1000
3
97 96 95
样例输出
4
0
-1
20
题目看起来跟汉诺塔很像,但是条件更苛刻。
不过由于n < 8,所以状态数最多是1!+2!+3!+…7!。
但是如果想模拟移动的过程,在移动过程中箱子会重叠,这样的话,所有状态的数目应该是1^1+2^2+3^3…7^7。
这个状态数目不是特别大。
而且对于1,12,123,1234,12345,123456,1234567这种状态的值都为0.
于是,就可以从这些为0的状态出发,去模拟箱子移动的过程,然后bfs求得所有状态的解。相当于一个倒推的过程。
首先肯定需要把所有数处理成连续的数,比如123456这样。这个处理方法有很多。
但是状态的存储是一个问题。
可以用一个结构体来存,那么里面会有一个长度为7的数组index[i],表示大小为i的箱子所在的位置。这样的话需要map来存结果,但是需要重载小于号。
用string存的话可以不用重载小于号,但是也需要map来保存结果。
但是这里map的效率是logn,经测时间很长。。
也就是说这个logn不能乘上去,虽然理论上计算复杂度应该够,但是实际上1S内无法处理。
也是说状态跟结果的映射关系需要在常数时间内完成。
由于状态最大是7777777,也就是说直接用十进制int来存状态的话是可以用一维数组来完成的。
网上也有用二进制状压的,每三位表示一个箱子的位置,这样最多21位就能表示所有箱子的状态,也就是2097152。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <map> #include <queue> #include <string> #define LL long long using namespace std; struct ARG { int val; int id; }arg[10]; bool cmpARG(ARG x, ARG y) { return x.val < y.val; } int n; int s[10]; int ans[8000000]; void bfs(int cnt) { int k[10], tmp, state, mi; queue<int> q; state = 0; for (int i = 1; i <= cnt; ++i) state = 10*state+i; ans[state] = 0; q.push(state); while (!q.empty()) { state = q.front(); q.pop(); tmp = state; for (int i = 0; i < cnt; ++i) { k[cnt-1-i] = tmp%10; tmp /= 10; } for (int i = 0; i < cnt; ++i) { mi = -1; for (int j = 0; j < i; ++j) { if (k[j] == k[i]) { mi = j; break; } } if (mi != -1) continue; if (k[i] > 1) { k[i]--; mi = -1; for (int j = 0; j < i; ++j) { if (k[j] == k[i]) { mi = j; break; } } tmp = 0; for (int i = 0; i < cnt; ++i) tmp = 10*tmp+k[i]; if (ans[tmp] == -1 && mi == -1) { ans[tmp] = ans[state]+1; q.push(tmp); } k[i]++; } if (k[i] < cnt) { k[i]++; mi = -1; for (int j = 0; j < i; ++j) { if (k[j] == k[i]) { mi = j; break; } } tmp = 0; for (int i = 0; i < cnt; ++i) tmp = 10*tmp+k[i]; if (ans[tmp] == -1 && mi == -1) { ans[tmp] = ans[state]+1; q.push(tmp); } k[i]--; } } } } void init() { memset(ans, -1, sizeof(ans)); for (int i = 1; i < 8; ++i) bfs(i); } void input() { scanf("%d", &n); for (int i = 0; i < n; ++i) { scanf("%d", &arg[i].val); arg[i].id = i; } sort(arg, arg+n, cmpARG); for (int i = 0; i < n; ++i) s[i]=arg[i].id+1; } void work() { if (n == 0) return; int k = 0; for (int i = 0; i < n; ++i) k = 10*k+s[i]; printf("%d\n", ans[k]); } int main() { //freopen("test.in", "r", stdin); init(); int T; scanf("%d", &T); for (int i = 0; i < T; ++i) { input(); work(); } return 0; }
ACM学习历程—Hihocoder 1233 Boxes(bfs)(2015北京网赛)
标签:
原文地址:http://www.cnblogs.com/andyqsmart/p/4836333.html