题意:一个正方形棋盘,三种棋子,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*+y*+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[]= {-,-,-,,,,,-}; //knight
int dy[]= {-,,,,,-,-,-}; Pair gra[N*N*][N*N*];
void buildGra()
{
for(int i=; i<n*n*; i++)
for(int j=; j<n*n*; j++)
gra[i][j]=Pair(,);
for(int i=; i<n; i++)
{
for(int j=; j<n; j++)
{
for(int k=; k<; k++)
for(int l=; l<; l++)
{
int t1=getState(i,j,k);
int t2=getState(i,j,l);
//cout<<"*"<<t1<<" "<<t2<<endl;
if(t1==t2)
gra[t1][t1]=Pair(,);
else
gra[t1][t2]=gra[t2][t1]=Pair(,);
}
for(int k=; k<; k++) //knight
{
int xx=i+dx[k];
int yy=j+dy[k];
if(xx>=&&xx<n&&yy>=&&yy<n)
{
int t1=getState(i,j,);
int t2=getState(xx,yy,);
gra[t1][t2]=gra[t2][t1]=Pair(,);
}
}
for(int k=-; k<=; k++) //bishop
for(int l=-; l<=; l++)
{
if(k==||l==)
continue;
int xx=i+k;
int yy=j+l;
while(xx>=&&xx<n&&yy>=&&yy<n)
{
int t1=getState(i,j,);
int t2=getState(xx,yy,);
gra[t1][t2]=gra[t2][t1]=Pair(,);
xx+=k;
yy+=l;
}
}
for(int k=i+; k<n; k++) //rook
{
int t1=getState(i,j,);
int t2=getState(k,j,);
gra[t1][t2]=gra[t2][t1]=Pair(,);
}
for(int k=j+; k<n; k++)
{
int t1=getState(i,j,);
int t2=getState(i,k,);
gra[t1][t2]=gra[t2][t1]=Pair(,);
}
}
}
} int main()
{
int R[],C[];
scanf("%d",&n);
for(int i=; i<n; i++)
for(int j=; j<n; j++)
{
int num;
scanf("%d",&num);
R[num]=i;
C[num]=j;
}
buildGra();
for(int k=; k<n*n*; k++)
for(int i=; i<n*n*; i++)
for(int j=; j<n*n*; j++)
if(gra[i][k]+gra[k][j]<gra[i][j])
gra[i][j]=gra[i][k]+gra[k][j];
Pair dp[N*N][];
dp[][]=dp[][]=dp[][]=Pair(,);
for(int i=; i<=n*n; i++)
{
dp[i][]=dp[i][]=dp[i][]=Pair(,);
int xx=R[i],yy=C[i];
for(int j=; j<; j++)
{
for(int k=; k<; k++)
{
int snow=getState(xx,yy,j);
int slst=getState(R[i-],C[i-],k);
if(dp[i-][k]+gra[slst][snow]<dp[i][j])
dp[i][j]=dp[i-][k]+gra[slst][snow];
}
}
}
Pair res(,);
for(int i=; i<; i++)
if(dp[n*n][i]<res)
res=dp[n*n][i];
printf("%d %d\n",res.sum(),res.rep);
return ;
}

codeforces_1065_D.three pieces_思维的更多相关文章

  1. [C#][算法] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

    用菜鸟的思维学习算法 -- 马桶排序.冒泡排序和快速排序 [博主]反骨仔 [来源]http://www.cnblogs.com/liqingwen/p/4994261.html  目录 马桶排序(令人 ...

  2. Photoshop、Illustrator思维导图笔记

    半年前学习Photoshop时记得的思维导图笔记,可能不是很全,常用的基本都记下了.

  3. CYQ.Data 从入门到放弃ORM系列:开篇:自动化框架编程思维

    前言: 随着CYQ.Data 开始回归免费使用之后,发现用户的情绪越来越激动,为了保持这持续的激动性,让我有了开源的念头. 同时,由于框架经过这5-6年来的不断演进,以前发的早期教程已经太落后了,包括 ...

  4. 计算机程序的思维逻辑 (8) - char的真正含义

    看似简单的char 通过前两节,我们应该对字符和文本的编码和乱码有了一个清晰的认识,但前两节都是与编程语言无关的,我们还是不知道怎么在程序中处理字符和文本. 本节讨论在Java中进行字符处理的基础 - ...

  5. 计算机程序的思维逻辑 (29) - 剖析String

    上节介绍了单个字符的封装类Character,本节介绍字符串类.字符串操作大概是计算机程序中最常见的操作了,Java中表示字符串的类是String,本节就来详细介绍String. 字符串的基本使用是比 ...

  6. 计算机程序的思维逻辑 (31) - 剖析Arrays

    数组是存储多个同类型元素的基本数据结构,数组中的元素在内存连续存放,可以通过数组下标直接定位任意元素,相比我们在后续章节介绍的其他容器,效率非常高. 数组操作是计算机程序中的常见基本操作,Java中有 ...

  7. 计算机程序的思维逻辑 (33) - Joda-Time

    Joda-Time上节介绍了JDK API中的日期和时间类,我们提到了JDK API的一些不足,并提到,实践中有一个广泛使用的日期和时间类库,Joda-Time,本节我们就来介绍Joda-Time.俗 ...

  8. 计算机程序的思维逻辑 (53) - 剖析Collections - 算法

    之前几节介绍了各种具体容器类和抽象容器类,上节我们提到,Java中有一个类Collections,提供了很多针对容器接口的通用功能,这些功能都是以静态方法的方式提供的. 都有哪些功能呢?大概可以分为两 ...

  9. 成吨提高开发效率:Intellij Shortcuts精简子集与思维模式

    在线精简cheatsheet备查表:intellij.linesh.twGithub项目:intellij-mac-frequent-keymap Intellij的快捷键多而繁杂,从官方推荐的key ...

随机推荐

  1. 如何获取板子上独有的ID号EXYNOS4412/Imx6ul【转】

    本文转载自:http://blog.csdn.net/u010871058/article/details/75637175 每个CPU,都有它固定的ID号,ID号就是这个CPU唯一的标识,它可能隐含 ...

  2. RK平台LCD调试说明【转】

    本文转载自:http://blog.csdn.net/u014770862/article/details/76274951?locationNum=2&fps=1 RK平台LCD调试说明 原 ...

  3. bzoj4594: [Shoi2015]零件组装机

    论静态查错的重要性...乱搞题真难调 首先这题看起来就是要分治检验了. 考虑对于区间[l,r],分成[l,p-1]和[p,r]使得这两个区间合并可以得到[l,r],并且要保证后面一个区间较大 设前一个 ...

  4. repo+manifests+git方式管理安卓代码

    repo+manifests+git方式管理安卓代码 1.repo的获取 repo只是google用Python脚本写的调用git的一个脚本,主要是用来下载.管理Android项目的软件仓库.(也就是 ...

  5. Lightoj 1140(数位DP)

    求一个区间内的数含有多少个0. dp[len][pre]表示长度为len的数,含有pre个0. 需要加一个标记,来表示前缀是否为0(可以是一串连续的0),如果前缀一直为0,就一直搜,如果前缀不为0,就 ...

  6. Python安装、配置图文详解

    原文地址:http://weixiaolu.iteye.com/blog/1617440 目录: 一. Python简介 二. 安装python 1. 在windows下安装 2. 在Linux下安装 ...

  7. bzoj 2784: [JLOI2012]时间流逝【树形期望dp】

    来自lyd课件 发现s和last(s),next(s)成树结构,然后把式子化简成kx+b的形式,做树形dp即可 #include<iostream> #include<cstdio& ...

  8. Qt事件系统之三:键盘事件

    QKeyEvent类用来描述一个键盘事件.当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键盘输人焦点的部件. QKeyEvent的key()函数可以获取具体的按键,对于Qt中给定的所有按键,可 ...

  9. 环境变量解释以及在Linux下的环境变量设置

    一.环境变量解释 环境变量是什么? 引用百度百科里面的解释:环境变量是操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息.例如Windows系统中的path环境变量,当要求 ...

  10. [SHOI2002]舞会

    Descriptio 某学校要召开一个舞会,已知有N名学生,有些学生曾经互相跳过舞.当然跳过舞的一定是一个男生和一个女生,在这个舞会上,要求被邀请的学生中任一对男生和女生互相都不能跳过舞.问最多可邀请 ...