zoukankan      html  css  js  c++  java
  • LG P7115 移球游戏

    Description

    小 C 正在玩一个移球游戏,他面前有 $n + 1$ 根柱子,柱子从 $1 sim n + 1$ 编号,其中 $1$ 号柱子、$2$ 号柱子、……、$n$ 号柱子上各有 $m$ 个球,它们自底向上放置在柱子上,$n + 1$ 号柱子上初始时没有球。这 $n imes m$ 个球共有 $n$ 种颜色,每种颜色的球各 $m$ 个。

    初始时一根柱子上的球可能是五颜六色的,而小 C 的任务是将所有同种颜色的球移到同一根柱子上,这是唯一的目标,而每种颜色的球最后放置在哪根柱子则没有限制。

    小 C 可以通过若干次操作完成这个目标,一次操作能将一个球从一根柱子移到另一根柱子上。更具体地,将 $x$ 号柱子上的球移动到 $y$ 号柱子上的要求为:

    1. $x$ 号柱子上至少有一个球;
    2. $y$ 号柱子上至多有 $m - 1$ 个球;
    3. 只能将 $x$ 号柱子最上方的球移到 $y$ 号柱子的最上方。

    小 C 的目标并不难完成,因此他决定给自己加加难度:在完成目标的基础上,使用的操作次数不能超过 $820000$。换句话说,小 C 需要使用至多 $820000$ 次操作完成目标。

    小 C 被难住了,但他相信难不倒你,请你给出一个操作方案完成小 C 的目标。合法的方案可能有多种,你只需要给出任意一种,题目保证一定存在一个合法方案。

    Solution

    当仅有两个柱子时,有这样的方案:

    钦定A柱上放置1号球,B柱上放置2号球,设A柱上原有$s$个1号球

    1.从B柱向C柱移动$s$个球

    2.将A柱上1号球置于B柱,2号球置于C柱

    3.从B柱向A柱移动$s$个球,从C柱向A柱移动$m-s$个球(以上的操作是为了给A柱排序)

    4.从B柱向C柱移动$m-s$个球(此时B柱空)

    5.从A柱向B柱移动$m-s$个球(此时A,B柱都符合要求但不满)

    6.从C柱按编号向A,B柱移动

    总操作次数为$5m-s$

    有多个柱时考虑分治,设阈值为$frac{l+r}{2}$,小于阈值的定为1号球,其余的为2号球,$O(n^2)$地枚举两根柱子进行操作使至少一根柱子满足要求

    总操作次数$5mnlog n$

    时间复杂度$O(5mn^2log n)$

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n,m,sta[55][405],top[55],sum,ans[820005][2],tot;
    bool tag[55];
    inline int read()
    {
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    void tran(int x,int y)
    {
        ans[++tot][0]=x,ans[tot][1]=y,sta[y][++top[y]]=sta[x][top[x]--];
    }
    void solve(int l,int r)
    {
        if(l==r) return;
        int mid=l+r>>1;
        memset(tag,false,sizeof(tag));
        for(int i=l;i<=mid;i++) for(int j=mid+1;j<=r;j++)
        {
            if(tag[i]||tag[j]) continue;
            sum=0;
            for(int k=1;k<=m;k++) sum+=(sta[i][k]<=mid)+(sta[j][k]<=mid);
            if(sum>=m)
            {
                sum=0;
                for(int k=1;k<=m;k++) sum+=(sta[i][k]<=mid);
                for(int k=1;k<=sum;k++) tran(j,n+1);
                for(int k=1;k<=m;k++)
                    if(sta[i][top[i]]<=mid) tran(i,j);
                    else tran(i,n+1);
                for(int k=1;k<=sum;k++) tran(j,i);
                for(int k=1;k<=m-sum;k++) tran(n+1,i);
                for(int k=1;k<=m-sum;k++) tran(j,n+1);
                for(int k=1;k<=m-sum;k++) tran(i,j);
                for(int k=1;k<=m;k++)
                    if(sta[n+1][top[n+1]]<=mid&&top[i]<m) tran(n+1,i);
                    else tran(n+1,j);
                tag[i]=true;
            }
            else
            {
                sum=0;
                for(int k=1;k<=m;k++) sum+=(sta[j][k]>mid);
                for(int k=1;k<=sum;k++) tran(i,n+1);
                for(int k=1;k<=m;k++)
                    if(sta[j][top[j]]>mid) tran(j,i);
                    else tran(j,n+1);
                for(int k=1;k<=sum;k++) tran(i,j);
                for(int k=1;k<=sum;k++) tran(n+1,j);
                for(int k=1;k<=m-sum;k++) tran(i,n+1);
                for(int k=1;k<=m-sum;k++) tran(j,i);
                for(int k=1;k<=m;k++)
                    if(sta[n+1][top[n+1]]>mid&&top[j]<m) tran(n+1,j);
                    else tran(n+1,i);
                tag[j]=true;
            }
        }
        solve(l,mid),solve(mid+1,r);
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) sta[i][++top[i]]=read();
        solve(1,n);
        printf("%d
    ",tot);
        for(int i=1;i<=tot;i++) printf("%d %d
    ",ans[i][0],ans[i][1]);
        return 0;
    }
    移球游戏
  • 相关阅读:
    AngularJS(17)-Angular小程序
    AngularJS(16)-路由
    AngularJS(15)-依赖注入
    AngularJS(14)-动画
    AngularJS(13)-包含
    AngularJS(12)-BootStrap集成
    AngularJS(11)-API
    AngularJS(10)-数据验证
    Mysql 备份和恢复.sql文件,导入.csv文件
    Mysql group_concat()
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14138386.html
Copyright © 2011-2022 走看看