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
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    图像检索(image retrieval)- 11
    图像检索(image retrieval)- 10相关
    Mock.js简易教程,脱离后端独立开发,实现增删改查功能
    Azure Monitor (3) 对虚拟机磁盘设置自定义监控
    Azure Monitor (1) 概述
    Azure SQL Managed Instance (2) 备份SQL MI
    Azure Virtual Network (17) Private Link演示
    Azure Virtual Network (16) Private Link
    Azure Virtual Network (15) Service Endpoint演示
    Azure Virtual Network (14) Service Endpoint服务终结点
  • 原文地址:https://www.cnblogs.com/mastervan/p/10975734.html
Copyright © 2011-2022 走看看