题意
4*n停车场,第二行和第三行是过道,第一行和第四行是车库,0表示空地。在过道的车可以上下左右四个方向随意走动,车一旦进入第一和第四行就不能动了。现在有k辆车(1~k)要停车,编号为 i 的车要停入编号为 i 的车库,保证车和车库的编号都只有一个。一辆车移动一下算一步,现在要把所有的车入库,请你输出一种20000步以内的解法,没有输出-1。
思路
我们让这些车在第二行和第三行兜圈子走就好了,如果哪个车可以停入对应的车库就让他停进去,其他的继续。
如果初始状态下,所有车都停不进去且没有空位,那么就无解。一旦有一个空位可以用于挪动车辆,我们照此方法就可以把所有车停进去。最坏情况下每个车都移动了一圈才停进去,移动次数为100*100+100,所以方案可行。
接下来就是个大模拟了…
为了方便我把第二行和第三行对接到了一起(按照图中转圈方向),第一行和第四行按照同样的方法对接到一起。
比如第一个样例:
4 5
1 2 0 4
1 2 0 4
5 0 0 3
0 5 0 3
变为:
2 10
1 2 0 4 3 0 5 0
1 2 0 4 3 0 0 5
这样的话第一行就是车库,第二行就是车所在的过道。
对于第一行第i个位置,如果 i/n=0 证明在第一列的 i%n+1 位置,否则就是在第四列的倒数 i%n+1 位置。
对于第二行第i个位置,如果 i/n=0 证明在第二列的 i%n+1 位置,否则就是在第三列的倒数 i%n+1 位置。
我们把第二行和第三行中的车和空地理解成一列火车在旋转,车头为一个空地,每次后面的车厢都往前走了一节。
在变换后的数组中其实就是每个数字都往后面移动了一位,最后一位变为第一位。但是,顺序是红色箭头,黑色的箭头,绿色箭头。一直旋转停车,直到所有车都入库,过程中如果是车的移动就用ans记录下路径。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 205;
int n, k, a[5][MAXN], s;//s是火车头
struct Node
{
int id, x, y;
Node(int id, int x, int y): id(id), x(x), y(y) {}
};
vector<Node> ans;
void park()//尝试停车
{
for (int i = 0; i < 2*n; i++) if (a[1][i] && a[1][i] == a[0][i])
{//入库,记录路径
ans.push_back(Node(a[1][i], i/n?4:1, i%n+1));
a[1][i] = 0; k--;
}
}
bool judge()//有解?
{
park();
for (int i = 0; i < 2*n; i++) if (!a[1][i]) return true;
return false;
}
void turn()
{
vector<Node> v1, v2;
int t = a[1][2*n-1];
for (int i = 2*n-1; i >= 1; i--)
{
a[1][i] = a[1][i-1];
if (a[1][i])//是车的移动,记录路径
{
if (i > s) v1.push_back(Node(a[1][i], i/n?3:2, i%n+1));//绿色箭头
else v2.push_back(Node(a[1][i], i/n?3:2, i%n+1));//红黑箭头
}
}
a[1][0] = t; if (t) v2.push_back(Node(t, 2, 1));
for (auto i: v2) ans.push_back(i);//红黑箭头
for (auto i: v1) ans.push_back(i);//绿色箭头
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++) scanf("%d", &a[0][i]);
for (int i = 0; i < n; i++) scanf("%d", &a[1][i]);
for (int i = 2*n-1; i >= n; i--) scanf("%d", &a[1][i]);
for (int i = 2*n-1; i >= n; i--) scanf("%d", &a[0][i]);
if (!judge()) { printf("-1\n"); return 0; } //判断无解
for (int i = 0; i < 2*n; i++) if(!a[1][i]) { s = i; break; } //找火车头
while (k)
{
turn(); park();//旋转,尝试停车
s = (s+1)%(2*n);
}
printf("%d\n", ans.size());
for (auto i: ans)
{
if (i.x == 3 || i.x == 4) i.y = n-i.y+1;//倒数变正数
printf("%d %d %d\n", i.id, i.x, i.y);
}
return 0;
}
/*
4 5
1 2 0 4
1 2 0 4
5 0 0 3
0 5 0 3
*/