P6892 [ICPC2014 WF] Baggage 题解

2024/06/29 Blog

这构造太抽象了,我做了一天。

解法

观察两个样例发现,所需最小步数是 $n$,考虑如何证明答案下界是 $n$。

这里使用比较经典的容分析,定义每个位置的容为两侧两个相邻和该位置相同的个数,一个状态的容为所有位置的容的和。初始状态的容为 $0$,目标状态的容为 $4 n - 4$,没进行一次操作最多使容增加 $4$,而第一次操作只能将中间的相邻行李移动到两侧的空位上,所以靠外的位置的容没办法增加,而我们期望的本来应该与外侧位置相邻的那个位置的容也没办法增加(就是说只能是内测和与内测相邻的两个位置的容增加),所以第一次移动只能使容增加 $2$,所以答案理论下届为 $n$ 次操作。

考虑如何达到理论下界。

考虑使用暴力搜索找 $n \le 6$ 的规律(因为我这个暴力当 $n=7$ 的时候已经跑不出来了)。

3

4

5

6

并没有发现什么很直观的规律,故考虑归纳构造。

依次由小到大尝试将 $n$ 仅花费 $x$ 次操作规约为 $n - x$,发现当 $x = 4$ 时可以实现(手玩过程非常漫长),如图。

图

但是很容易发现 $n = 7$ 的情况不能规约为 $n = 3$ 的情况,否则中间会有两个空位,所以还要手玩一下 $n = 7$ 的情况。

7

然后就做完了。

代码

暴力核心代码

int n,a[100],ans;
inline bool check2(int l,int r,int val)
{
    for(int i=l;i<=r;i++) if(a[i]!=val) return false;
    return true;
}
inline bool check()
{
    for(int i=0;i<=20;i++) if(a[i]==1) return check2(i,i+n-1,1) && check2(i+n,i+n*2-1,2);
    return false;
}
inline void print()
{
    for(int i=0;i<=21;i++) out<<a[i]<<' ';
    out<<'\n';
}
inline bool dfs(int dep)
{
    if(dep==n)
    {
        if(check())
        {
            print();
            ans++;
            return true;
        }
        return false;
    }
    bool flag=false;
    for(int i=0,tmp1,tmp2;i<=20;i++)
        if(a[i] && a[i+1])
            for(int j=0,fl;j<=20;j++)
                if(!a[j] && !a[j+1])
                {
                    tmp1=a[i],tmp2=a[i+1],a[j]=a[i],a[j+1]=a[i+1],a[i]=a[i+1]=0,fl=false;
                    if(dfs(dep+1)) flag=fl=true;
                    a[j]=a[j+1]=0,a[i]=tmp1,a[i+1]=tmp2;
                    if(fl) print();
                }
    return flag;
}

归纳构造代码

#include<bits/stdc++.h>
namespace fast_IO
{
    /**
     * useless fastio
     */
};
using namespace fast_IO;
int n;
inline void dfs(int n,int l,int r)
{
    if(n==3)
    {
        out<<l+1<<" to "<<l-2<<'\n';
        out<<r-1<<" to "<<l+1<<'\n';
        out<<l+2<<" to "<<-3<<'\n';
        return;
    }
    if(n==4)
    {
        out<<r-2<<" to "<<l-2<<'\n';
        out<<l+2<<" to "<<r-2<<'\n';
        out<<l-1<<" to "<<l+2<<'\n';
        out<<r-1<<" to "<<l-1<<'\n';
        return;
    }
    if(n==5)
    {
        out<<r-2<<" to "<<l-2<<'\n';
        out<<l+2<<" to "<<r-2<<'\n';
        out<<r-4<<" to "<<l+2<<'\n';
        out<<l-1<<" to "<<r-4<<'\n';
        out<<r-1<<" to "<<l-1<<'\n';
        return;
    }
    if(n==6)
    {
        out<<r-2<<" to "<<l-2<<'\n';
        out<<r-5<<" to "<<r-2<<'\n';
        out<<l+1<<" to "<<r-5<<'\n';
        out<<l+5<<" to "<<l+1<<'\n';
        out<<l-1<<" to "<<l+5<<'\n';
        out<<r-1<<" to "<<l-1<<'\n';
        return;
    }
    if(n==7)
    {
        out<<r-6<<" to "<<l-2<<'\n';
        out<<l+4<<" to "<<r-6<<'\n';
        out<<r-2<<" to "<<l+4<<'\n';
        out<<l+2<<" to "<<r-2<<'\n';
        out<<r-5<<" to "<<l+2<<'\n';
        out<<l-1<<" to "<<r-5<<'\n';
        out<<r-1<<" to "<<l-1<<'\n';
        return;
    }
    out<<r-2<<" to "<<l-2<<'\n';
    out<<l+2<<" to "<<r-2<<'\n';
    dfs(n-4,l+4,r-4);
    out<<l-1<<" to "<<r-5<<'\n';
    out<<r-1<<" to "<<l-1<<'\n';
}
int main()
{
    in>>n;
    dfs(n,1,2*n);
    fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);
    return 0;
}
对我博客最大的鼓励来自于你的评论(什么玩梗),欢迎选择 来回复, 也可以在 GitHub discussion 留言。

Search

    公告

    博主这下真摆烂了。我下辈子也不碰 Jekyll 和 MathJax 了!
    留言板,现在博主的精神状态非常好,有事烧纸。

    联系方式

    QQ: 33299235
    email: 33299235@qq.com
    Gmail: scp020.cn@gmail.com

    本人的其它个人主页

    洛谷
    CSDN

    友链

    拜谢stevehim(已退役,祝好)
    拜谢日记
    拜谢cppomstar

    views counting

    Document

    Table of Contents