CodeForces ~ 996C ~ Tesla (思维 + 模拟)

题意

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
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值