• codeforces_1065_D.three pieces_思维


    题意:一个正方形棋盘,三种棋子,knight:像中国象棋中的马一样走;bishop:斜着走;rook:中国象棋中的车。棋盘中每个格子中标着1--n*n的互不相同的数字,从1开始任选一种棋子开始走,在每个格子,要么移动棋子,要么更换一种棋子,每个格子可以重复走,移动或更换都算作一步。问从1按增序走到n*n,至少需要多少步,相同步数情况下选择替换次数最少的方案。

    思路:这道题的难点在于每一步可以更换棋子,算上棋子种类,一共3维[i][j][p],每走一步是从[i][j][p]走到[i'][j'][p'],在这种情况下问题有点复杂。但是可以发现任何一点到另一点最多可以3步走到,bishop和rook这两种非常容易算出步数,然后再通过dfs搜索一下knight需要的步数,每走一步验证三种情况,感觉应该可以,改天试试。实现时发现一个问题,可以先走一步再替换一次,再走一步,这样也是3步,这种情况不好处理。

    另一种思路,官方题解的思路。为了化简问题,将[i][j][k]当做一种状态,用i*n*3+j*3+k映射为一个整数,由此可以构建状态的邻接矩阵,再使用最短路算法求出每个状态之间的最短路,最后按顺序dp一下。这个方法比较巧妙,将3维的状态映射到1维上,值得思考。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define LL long long
    #define N 12
    int n;
    
    int getState(int x,int y,int p)
    {
        return x*n*3+y*3+p;
    }
    
    struct Pair
    {
        int mov,rep;
        Pair() {}
        Pair(int m,int r)
        {
            mov=m;
            rep=r;
        }
        bool operator < (const Pair t)const
        {
            if(mov+rep==t.mov+t.rep)
                return rep<t.rep;
            else
                return mov+rep<t.mov+t.rep;
        }
        Pair operator + (const Pair t)const
        {
            Pair ret;
            ret.mov=mov+t.mov;
            ret.rep=rep+t.rep;
            return ret;
        }
        int sum()
        {
            return mov+rep;
        }
    };
    
    int dx[8]= {-2,-2,-1,1,2,2,1,-1}; //knight
    int dy[8]= {-1,1,2,2,1,-1,-2,-2};
    
    Pair gra[N*N*3][N*N*3];
    void buildGra()
    {
        for(int i=0; i<n*n*3; i++)
            for(int j=0; j<n*n*3; j++)
                gra[i][j]=Pair(1000,1000);
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                for(int k=0; k<3; k++)
                    for(int l=0; l<3; l++)
                    {
                        int t1=getState(i,j,k);
                        int t2=getState(i,j,l);
                        //cout<<"*"<<t1<<" "<<t2<<endl;
                        if(t1==t2)
                            gra[t1][t1]=Pair(0,0);
                        else
                            gra[t1][t2]=gra[t2][t1]=Pair(0,1);
                    }
                for(int k=0; k<8; k++) //knight
                {
                    int xx=i+dx[k];
                    int yy=j+dy[k];
                    if(xx>=0&&xx<n&&yy>=0&&yy<n)
                    {
                        int t1=getState(i,j,0);
                        int t2=getState(xx,yy,0);
                        gra[t1][t2]=gra[t2][t1]=Pair(1,0);
                    }
                }
                for(int k=-1; k<=1; k++) //bishop
                    for(int l=-1; l<=1; l++)
                    {
                        if(k==0||l==0)
                            continue;
                        int xx=i+k;
                        int yy=j+l;
                        while(xx>=0&&xx<n&&yy>=0&&yy<n)
                        {
                            int t1=getState(i,j,1);
                            int t2=getState(xx,yy,1);
                            gra[t1][t2]=gra[t2][t1]=Pair(1,0);
                            xx+=k;
                            yy+=l;
                        }
                    }
                for(int k=i+1; k<n; k++) //rook
                {
                    int t1=getState(i,j,2);
                    int t2=getState(k,j,2);
                    gra[t1][t2]=gra[t2][t1]=Pair(1,0);
                }
                for(int k=j+1; k<n; k++)
                {
                    int t1=getState(i,j,2);
                    int t2=getState(i,k,2);
                    gra[t1][t2]=gra[t2][t1]=Pair(1,0);
                }
            }
        }
    }
    
    int main()
    {
        int R[105],C[105];
        scanf("%d",&n);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                int num;
                scanf("%d",&num);
                R[num]=i;
                C[num]=j;
            }
        buildGra();
        for(int k=0; k<n*n*3; k++)
            for(int i=0; i<n*n*3; i++)
                for(int j=0; j<n*n*3; j++)
                    if(gra[i][k]+gra[k][j]<gra[i][j])
                        gra[i][j]=gra[i][k]+gra[k][j];
        Pair dp[N*N][3];
        dp[1][0]=dp[1][1]=dp[1][2]=Pair(0,0);
        for(int i=2; i<=n*n; i++)
        {
            dp[i][0]=dp[i][1]=dp[i][2]=Pair(1000,1000);
            int xx=R[i],yy=C[i];
            for(int j=0; j<3; j++)
            {
                for(int k=0; k<3; k++)
                {
                    int snow=getState(xx,yy,j);
                    int slst=getState(R[i-1],C[i-1],k);
                    if(dp[i-1][k]+gra[slst][snow]<dp[i][j])
                        dp[i][j]=dp[i-1][k]+gra[slst][snow];
                }
            }
        }
        Pair res(1000,1000);
        for(int i=0; i<3; i++)
            if(dp[n*n][i]<res)
                res=dp[n*n][i];
        printf("%d %d
    ",res.sum(),res.rep);
        return 0;
    }
  • 相关阅读:
    xdebug安装教程
    如何查看Linux操作系统的位数
    getconf命令【一天一个命令】
    redis 数据类型详解 以及 redis适用场景场合
    Redis和Memcache对比及选择
    无交换机实现集群网络互联
    性能调优攻略
    Chrome 插件集推荐
    在 Linux 下将 PNG 和 JPG 批量互转的四种方法
    Flashback for MySQL 5.7
  • 原文地址:https://www.cnblogs.com/jasonlixuetao/p/9813615.html
Copyright © 2020-2023  润新知