题目大意:给你一个棋盘,你需要控制棋子依次经过编号为1~n的所有点,棋子的可以是车,马,象,都依照国际象棋的行棋方式,每走一步消耗1单位时间,但每次更换棋子都需要额外1单位时间,求经过所有点需要的最少时间 ,如果多种方案需要的最少时间相同,输出更换棋子次数最少的那个

有的机房老人用了记忆化搜索,但写起来好像很蛋疼。神仙学弟phy想了一个多元最短路,简洁好写

每个点有三种状态,先暴力建边。

然后根据点的编号从小到大,以每个点为源点跑一次两元最短路

注意,不能在个点都记录超级源点/汇点,因为这样做会让更换棋子的步骤失效!

所以,每当跑完某个点的最短路时,先记录当前下一个点的三种状态的花费,从下一个编号的点开始跑时,先清数组,再把上次记录的花费扔到起始状态里,再去跑这个点为源点的最短路
接下来就是多元最短路了,可以用重载运算符,比较好写

 #include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 15
#define M 500
#define inf 66666666
using namespace std; int n,cte,num;
int mp[N][N],id[N][N][],head[M];
int px[M],py[M];
struct node{int d,w;
friend bool operator < (const node &s1,const node &s2){
if(s1.d!=s2.d) return s1.d<s2.d;
else return s1.w<s2.w;
}node(int d,int w):d(d),w(w){} node(){}
};
struct Edge{int to,nxt,d,w;}edge[M*];
void ae(int u,int v,int d,int w){
cte++;edge[cte].to=v,edge[cte].nxt=head[u];
edge[cte].d=d,edge[cte].w=w,head[u]=cte;
}
inline int check(int x,int y)
{return <=x&&x<=n&&<=y&&y<=n;}
void Build_Edge()
{
int s0,s1,s2,s3,t1,t2,t3;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
s1=id[i][j][],s2=id[i][j][],s3=id[i][j][];
ae(s1,s2,,),ae(s2,s1,,),ae(s1,s3,,),ae(s3,s1,,),ae(s2,s3,,),ae(s3,s2,,);
for(int x=;x<=n;x++){if(!check(i+x,j))break;t1=id[i+x][j][],ae(s1,t1,,);}
for(int x=;x<=n;x++){if(!check(i,j+x))break;t1=id[i][j+x][],ae(s1,t1,,);}
for(int x=;x<=n;x++){if(!check(i-x,j))break;t1=id[i-x][j][],ae(s1,t1,,);}
for(int x=;x<=n;x++){if(!check(i,j-x))break;t1=id[i][j-x][],ae(s1,t1,,);} for(int x=;x<=n;x++){if(!check(i+x,j+x))break;t3=id[i+x][j+x][],ae(s3,t3,,);}
for(int x=;x<=n;x++){if(!check(i-x,j+x))break;t3=id[i-x][j+x][],ae(s3,t3,,);}
for(int x=;x<=n;x++){if(!check(i+x,j-x))break;t3=id[i+x][j-x][],ae(s3,t3,,);}
for(int x=;x<=n;x++){if(!check(i-x,j-x))break;t3=id[i-x][j-x][],ae(s3,t3,,);} if(check(i+,j+))t2=id[i+][j+][],ae(s2,t2,,);
if(check(i+,j+))t2=id[i+][j+][],ae(s2,t2,,);
if(check(i-,j-))t2=id[i-][j-][],ae(s2,t2,,);
if(check(i-,j-))t2=id[i-][j-][],ae(s2,t2,,);
if(check(i+,j-))t2=id[i+][j-][],ae(s2,t2,,);
if(check(i+,j-))t2=id[i+][j-][],ae(s2,t2,,);
if(check(i-,j+))t2=id[i-][j+][],ae(s2,t2,,);
if(check(i-,j+))t2=id[i-][j+][],ae(s2,t2,,);
} }
node dis[M],lst[];int use[M];
node SPFA()
{
int s1,s2,s3,t1,t2,t3;
queue<int>q;node tmp;
for(int i=;i<n*n;i++)
{
memset(dis,0x3f,sizeof(dis));
memset(use,,sizeof(use));
s1=id[px[i]][py[i]][];
s2=id[px[i]][py[i]][];
s3=id[px[i]][py[i]][];
dis[s1]=lst[],dis[s2]=lst[],dis[s3]=lst[];
use[s1]=,use[s2]=,use[s3]=;
q.push(s1),q.push(s2),q.push(s3);
while(!q.empty())
{
int x=q.front();q.pop();
tmp=dis[x];
for(int j=head[x];j;j=edge[j].nxt){
int v=edge[j].to;
tmp.d+=edge[j].d,tmp.w+=edge[j].w;
if(tmp<dis[v]){ dis[v]=tmp;
if(!use[v]) use[v]=,q.push(v);
}tmp=dis[x];
}use[x]=;
}
t1=id[px[i+]][py[i+]][];
t2=id[px[i+]][py[i+]][];
t3=id[px[i+]][py[i+]][];
lst[]=dis[t1],lst[]=dis[t2],lst[]=dis[t3];
}
node ret;ret.d=inf,ret.w=inf;
s1=id[px[n*n]][py[n*n]][];
s2=id[px[n*n]][py[n*n]][];
s3=id[px[n*n]][py[n*n]][];
if(dis[s1]<ret) ret=dis[s1];
if(dis[s2]<ret) ret=dis[s2];
if(dis[s3]<ret) ret=dis[s3];
return ret;
} int main()
{
//freopen("t1.in","r",stdin);
scanf("%d",&n);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
scanf("%d",&mp[i][j]),id[i][j][]=++num,id[i][j][]=++num,
id[i][j][]=++num,px[mp[i][j]]=i,py[mp[i][j]]=j;
Build_Edge();
node ret=SPFA();
printf("%d %d\n",ret.d,ret.w);
return ;
}

CF1065D Three Pieces (多元最短路)的更多相关文章

  1. Codeforces 938 D. Buy a Ticket (dijkstra 求多元最短路)

    题目链接:Buy a Ticket 题意: 给出n个点m条边,每个点每条边都有各自的权值,对于每个点i,求一个任意j,使得2×d[i][j] + a[j]最小. 题解: 这题其实就是要我们求任意两点的 ...

  2. CF1065D Three Pieces

    题目描述:给出一个n*n的棋盘,棋盘上每个格子有一个值.你有一个子,要求将这个子从1移到n*n(去k时可以经过比k大的点). 开局时它可以作为车,马,相(国际象棋).每走一步耗费时间1.你也可以中途将 ...

  3. HDU 2544 最短路 http://acm.hdu.edu.cn/showproblem.php?pid=2544

    //代码: //方法1:Dijkstra's Algorithm #include<stdio.h> #include<math.h> #include<string.h ...

  4. poj 1125 Stockbroker Grapevine(最短路 简单 floyd)

    题目:http://poj.org/problem?id=1125 题意:给出一个社交网络,每个人有几个别人可以传播谣言,传播谣言需要时间.问要使得谣言传播的最快,应该从那个人开始传播谣言以及使得所有 ...

  5. Floyd —Warshall(最短路及其他用法详解)

    一.多元最短路求法 多元都求出来了,单源的肯定也能求. 思想是动态规划的思想:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B.所以,我们假设Dis(A ...

  6. NOIP2016参赛总结

    NOIP2016复赛参赛总结 noip2016终于结束了,对于这次的比赛我只想说,死得好惨.(画风突变) 赛前趁着期中考浪到常州去培训,一天两套模拟的训练真的是心力交瘁(好吧没这么严重),不过那些模拟 ...

  7. Codeforces 196E Opening Portals MST (看题解)

    Opening Portals 我们先考虑如果所有点都是特殊点, 那么就是对整个图求个MST. 想在如果不是所有点是特殊点的话, 我们能不能也 转换成求MST的问题呢? 相当于我们把特殊点扣出来, 然 ...

  8. GDOI2018 新的征程

    看标题您一定以为考得很好.. Bad ending.想看美好结局的出门右转其他大佬博客. Day0 早上去车站的时候心情挺好.倒不是因为自己做足了准备,也不是因为预感到有好事发生,而是心情不好也没有用 ...

  9. [WC2015]未来程序(提交答案)

    sub1:ans=a*b%c,龟速乘即可. #include <stdio.h> #include <stdlib.h> unsigned long long a, b, c, ...

随机推荐

  1. LeetCode Golang 6. Z 字形变换

    6. Z 字形变换 将一个给定字符串根据给定的行数,以从上往下.从左到右进行 Z 字形排列. 比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下: L ...

  2. spring的JdbcTemplate

    一.首先配置JdbcTemplate: 要使用Jdbctemplate 对象来完成jdbc 操作.通常情况下,有三种种方式得到JdbcTemplate 对象.       第一种方式:我们可以在自己定 ...

  3. pupload上传插件问题整理

    前些日子公司网站需要开发一个类似与百度文库上传文档的功能,实现文档的批量上传.展示以及继续上传的功能.开发完成后,通过在多版浏览器下的使用,发现了一系列问题,特总结于下,以免来者在这些问题上耗费太多时 ...

  4. C#RichTextBox复制并跳转指定行

    方法一: rTxt.Focus(); //设置文本框中选定的文本起始点 为 指定行数第一个字符的索引 rTxt.SelectionStart = rTxt.GetFirstCharIndexFromL ...

  5. BZOJ 2119 股市的预测 (后缀数组+RMQ)

    题目大意:求一个字符串中形如$ABA$的串的数量,其中$B$的长度是给定的 有点像[NOI2016]优秀的拆分这道题 先对序列打差分,然后离散,再正反跑$SA$,跑出$st$表 进入正题 $ABA$串 ...

  6. Linux之awk使用

    基本语法 $n :当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段 $0:执行过程中当前行的文本内容 \t:制表符 \n:换行符 -F'[:#/]' : 定义三个分隔符,注意有-F ...

  7. Redis:基础知识及其常用数据类型和关键字

    Redis: Redis是什么: REmote DIctionary Server(远程字典服务器) 是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(Key-Value)分布式内存数 ...

  8. ASP.NET-datatable转换成list对象

    #region 讲DataTable转换为List对象 /// <summary> /// 利用反射将DataTable转换为List<T>对象 /// </summar ...

  9. HDU 4335 Contest 4

    利用降幂公式..呃,还是自己去搜题解吧.知道降幂公式后,就不难了. #include <iostream> #include <cstdio> #include <alg ...

  10. leveldb学习:sstable(2)

    block写入:block_builder block.h和.cc里定义了block的entry存储格式和restart,提供了entry的查找接口以及迭代器.那么怎样往写block里写entry呢? ...