zoukankan      html  css  js  c++  java
  • [状压DP]JZOJ 1303 骑士

    Description

      用字符矩阵来表示一个8x8的棋盘,'.'表示是空格,'P'表示人质,'K'表示骑士。
      每一步,骑士可以移动到他周围的8个方格中的任意一格。如果你移动到的格子中有人质(即'P'),你将俘获他。但不能移到出棋盘或当前是'K'的格子中。
      请问最少要移动多少步骑士才能俘获所有的人质。 
     

    Input

      第一行一个整数N(<=5),表示有多少个棋盘。即多组测试数据。
      每一组有8行,每行8个字符。字符只有'.',大写'P',大写'K'三种字符。'P'和'K'的个数范围都在[1,10]。

    Output

      有N行,每行只一个整数,相应棋盘俘获全部人质所需要的最少步数。
     

    Sample Input

    输入1:
    1
    .PPPPKP.
    ........
    ........
    ........
    ........
    ........
    ........
    ........
    
    输入2:
    2
    P......P
    ........
    ........
    ........
    ...KK...
    ........
    ........
    P......P
    .....P.P
    ..K....P
    ....K...
    ..PP...P
    ...K..KK
    ........
    K.......
    KP.K....
    

    Sample Output

    输出1:
    6
    
    输出2:
    20
    9
     

    Data Constraint

    分析

    观察到人质和骑士数量很少,而且距离可知,考虑状压DP

    预处理距离即可

    我们设f[i][j][k]表示i个骑士最后一个解救的人质是j,总共解救的人质状态为k的最小步数

    转移方程易得:

    f[i][j][k|(1<<j-1)]=Min{f[i][l][k] (l=1~pcnt,l∈k,j不属于k)

    再设g[i][j]表示i个骑士解救的人质状态为j的最小步数

    那么方程也易得

    k为j的子集

    g[i][j]=Min{g[i-1][k]+Min{f[i][1~pcnt][j^k]

    然后这样会T,我们发现第二个Min可以在转移f时顺便搞出来,就没了

    然后判子集是:(j^k)+k==j,我傻傻地用j&k==k……然后WA了一天

    #include <iostream> 
    #include <cstdio>
    #include <memory.h>
    #include <cmath>
    using namespace std;
    int n,mxn,pcnt,kcnt;
    int p[11][2],k[11][2],dis[11][11];
    int f[11][11][1<<11],g[11][1<<11],m[11][1<<11];
    
    int main() {
        for (scanf("%d",&n);n;n--) {
            pcnt=kcnt=0;
            memset(f,0x0f,sizeof f);memset(g,0x0f,sizeof g);memset(m,0x0f,sizeof m);
            for (int i=1;i<=8;i++)
                for (int j=1;j<=8;j++) {
                    char c;
                    do {
                        scanf("%c",&c);
                    }
                    while (c!='.'&&c!='P'&&c!='K');
                    if (c=='P') p[++pcnt][0]=i,p[pcnt][1]=j;
                    if (c=='K') k[++kcnt][0]=i,k[kcnt][1]=j;
                }
            mxn=1<<pcnt;
            g[0][0]=0;
            for (int i=1;i<=kcnt;i++) m[i][0]=0;
            for (int i=1;i<pcnt;i++)
                for (int j=i+1;j<=pcnt;j++)
                    dis[i][j]=dis[j][i]=max(abs(p[i][0]-p[j][0]),abs(p[i][1]-p[j][1]));
            for (int i=1;i<=kcnt;i++) {
                for (int j=1;j<=pcnt;j++)
                    f[i][j][1<<j-1]=max(abs(k[i][0]-p[j][0]),abs(k[i][1]-p[j][1])),m[i][1<<j-1]=f[i][j][1<<j-1];
                for (int j=1;j<mxn;j++)
                    for (int k=1;k<=pcnt;k++)
                        if (!(j&(1<<k-1)))
                            for (int l=1;l<=pcnt;l++)
                                if (j&(1<<l-1)) f[i][k][j|(1<<k-1)]=min(f[i][k][j|(1<<k-1)],f[i][l][j]+dis[l][k]),
                                m[i][j|(1<<k-1)]=min(m[i][j|(1<<k-1)],f[i][k][j|(1<<k-1)]);
                for (int j=0;j<mxn;j++)
                    for (int k=0;k<=j;k++)
                        if ((j^k)+k==j&&j!=k)
                            g[i][j]=min(g[i][j],g[i-1][k]+m[i][j^k]);
                            else if (j==k) g[i][j]=min(g[i][j],g[i-1][k]);
            }
            printf("%d
    ",g[kcnt][mxn-1]);
        }
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    windows下编译及使用libevent
    安装和使用memcached
    BroadcastReceiver插件化解决方案
    Service插件化解决方案
    Activity插件化解决方案
    换肤-插件化
    资源的插件化
    startActivity进行Hook
    代理模式
    对反射的封装
  • 原文地址:https://www.cnblogs.com/mastervan/p/10975734.html
Copyright © 2011-2022 走看看