Description
用字符矩阵来表示一个8x8的棋盘,'.'表示是空格,'P'表示人质,'K'表示骑士。
每一步,骑士可以移动到他周围的8个方格中的任意一格。如果你移动到的格子中有人质(即'P'),你将俘获他。但不能移到出棋盘或当前是'K'的格子中。
请问最少要移动多少步骑士才能俘获所有的人质。
每一步,骑士可以移动到他周围的8个方格中的任意一格。如果你移动到的格子中有人质(即'P'),你将俘获他。但不能移到出棋盘或当前是'K'的格子中。
请问最少要移动多少步骑士才能俘获所有的人质。
Input
第一行一个整数N(<=5),表示有多少个棋盘。即多组测试数据。
每一组有8行,每行8个字符。字符只有'.',大写'P',大写'K'三种字符。'P'和'K'的个数范围都在[1,10]。
每一组有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\n",g[kcnt][mxn-1]); } }