题目链接:http://codeforces.com/contest/1065/problem/D
题意:
给你三种棋子,和一个n*n大小的棋盘,棋盘上是1~n*n的不同数字,你可以任意选择一种棋子从数字1的位置开始,每种棋子都有自己的走法,骑士是马字条,法师可以在45°的斜角上走到任意位置,石头是垂直方向上走到任意位置,每走一次算一次操作,你在走到一个位置时都可以换其他的棋子(当然这也算增加一次操作),问你走到n*n这个位置上最少的操作数和这个操作数下最少
做法:
下面代码中有部分备注了,dp[x][y][k][t][z]是走到第x,y这个点 角色为k 换了t次角色 走过了z个点的最小步数,每次都要判断换棋子的情况即可,就是要注意细节。。表示bug de了我好久。。心塞,这里还有个问题,就是我用了优先队列答案反而是错的,用队列就可以过了,我想可能队列更像是模拟了真实情况下的操作,没有打乱内部顺序吧,毕竟每个情况只会被走到一次,可能优先队列在某种情况下只是在前面占优势,最后还是其他的情况好。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=105;
const int inf = 0x3f3f3f;
typedef pair<int,int> pii;
//0为骑士,1为牧师,2为石头
int dp[15][15][3][50][105],n,mp[15][15];
//dp[x][y][k][t][z]
//走到第x,y这个点 角色为k 换了t次角色 走过了z个点的最小步数
int dir0[8][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
int dir1[4][2]={{1,1},{1,-1},{-1,1},{-1,-1}};
int dir2[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
int x,y,k,t,z;
node(){}
node(int x,int y,int k,int t,int z):x(x),y(y),k(k),t(t),z(z){}
/*bool operator < (const node &a)const{
if(z==a.z){
if(t==a.t) return dp[x][y][k][t][z]>dp[a.x][a.y][a.k][a.t][a.z];
else return t>a.t;
}
return z>a.z;
}*/
};
queue<node> q;
int ck(int x,int y){
if(x>0&&x<=n&&y>0&&y<=n) return 1;
return 0;
}
void deal0(node tmp){
for(int i=0;i<3;i++){
if(i!=tmp.k){
if(dp[tmp.x][tmp.y][i][tmp.t+1][tmp.z]==-1){
dp[tmp.x][tmp.y][i][tmp.t+1][tmp.z]=dp[tmp.x][tmp.y][tmp.k][tmp.t][tmp.z]+1;
//printf("dp[%d][%d][%d][%d][%d] = %d\n",tmp.x,tmp.y,i,tmp.t+1,tmp.z,dp[tmp.x][tmp.y][i][tmp.t+1][tmp.z]);
q.push(node(tmp.x,tmp.y,i,tmp.t+1,tmp.z));
}
}
}
}
void deal1(node tmp,int nx,int ny){
int zz=tmp.z;
if(mp[nx][ny]==tmp.z+1) zz++;
if(dp[nx][ny][tmp.k][tmp.t][zz]==-1){
dp[nx][ny][tmp.k][tmp.t][zz]=dp[tmp.x][tmp.y][tmp.k][tmp.t][tmp.z]+1;
//printf("dp[%d][%d][%d][%d][%d] = %d\n",nx,ny,tmp.k,tmp.t,zz,dp[nx][ny][tmp.k][tmp.t][zz]);
q.push(node(nx,ny,tmp.k,tmp.t,zz));
}
}
void bfs(int sx,int sy){
dp[sx][sy][0][0][1]=dp[sx][sy][1][0][1]=dp[sx][sy][2][0][1]=0;
q.push(node(sx,sy,0,0,1));
q.push(node(sx,sy,1,0,1));
q.push(node(sx,sy,2,0,1));
while(!q.empty()){
node tmp=q.front(); q.pop();
deal0(tmp);
if(tmp.k==0){
for(int i=0;i<8;i++){
int nx=tmp.x+dir0[i][0],ny=tmp.y+dir0[i][1];
if(ck(nx,ny))
deal1(tmp,nx,ny);
}
}
else if(tmp.k==1){
for(int i=0;i<4;i++){
int nx=tmp.x+dir1[i][0],ny=tmp.y+dir1[i][1];
while(ck(nx,ny)){
deal1(tmp,nx,ny);
nx+=dir1[i][0];
ny+=dir1[i][1];
}
}
}
else{
for(int i=0;i<4;i++){
int nx=tmp.x+dir2[i][0],ny=tmp.y+dir2[i][1];
while(ck(nx,ny)){
deal1(tmp,nx,ny);
nx+=dir2[i][0];
ny+=dir2[i][1];
}
}
}
}
}
int main() {
int sx,sy,ex,ey;
scanf("%d",&n);
rep(i,1,n){
rep(j,1,n){
scanf("%d",&mp[i][j]);
if(mp[i][j]==1) sx=i,sy=j;
else if(mp[i][j]==n*n) ex=i,ey=j;
}
}
memset(dp,-1,sizeof(dp));
bfs(sx,sy);
int ans1=100000000,ans2=200;
rep(i,0,2){
rep(j,0,45){
if(dp[ex][ey][i][j][n*n]!=-1){
ans1=min(ans1,dp[ex][ey][i][j][n*n]);
}
}
}
rep(i,0,2){
rep(j,0,45){
if(dp[ex][ey][i][j][n*n]==ans1){
ans2=min(ans2,j);
}
}
}
printf("%d %d\n",ans1,ans2);
return 0;
}