CF1065D Three Pieces (多元最短路)
题目大意:给你一个棋盘,你需要控制棋子依次经过编号为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 (多元最短路)的更多相关文章
- Codeforces 938 D. Buy a Ticket (dijkstra 求多元最短路)
题目链接:Buy a Ticket 题意: 给出n个点m条边,每个点每条边都有各自的权值,对于每个点i,求一个任意j,使得2×d[i][j] + a[j]最小. 题解: 这题其实就是要我们求任意两点的 ...
- CF1065D Three Pieces
题目描述:给出一个n*n的棋盘,棋盘上每个格子有一个值.你有一个子,要求将这个子从1移到n*n(去k时可以经过比k大的点). 开局时它可以作为车,马,相(国际象棋).每走一步耗费时间1.你也可以中途将 ...
- HDU 2544 最短路 http://acm.hdu.edu.cn/showproblem.php?pid=2544
//代码: //方法1:Dijkstra's Algorithm #include<stdio.h> #include<math.h> #include<string.h ...
- poj 1125 Stockbroker Grapevine(最短路 简单 floyd)
题目:http://poj.org/problem?id=1125 题意:给出一个社交网络,每个人有几个别人可以传播谣言,传播谣言需要时间.问要使得谣言传播的最快,应该从那个人开始传播谣言以及使得所有 ...
- Floyd —Warshall(最短路及其他用法详解)
一.多元最短路求法 多元都求出来了,单源的肯定也能求. 思想是动态规划的思想:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B.所以,我们假设Dis(A ...
- NOIP2016参赛总结
NOIP2016复赛参赛总结 noip2016终于结束了,对于这次的比赛我只想说,死得好惨.(画风突变) 赛前趁着期中考浪到常州去培训,一天两套模拟的训练真的是心力交瘁(好吧没这么严重),不过那些模拟 ...
- Codeforces 196E Opening Portals MST (看题解)
Opening Portals 我们先考虑如果所有点都是特殊点, 那么就是对整个图求个MST. 想在如果不是所有点是特殊点的话, 我们能不能也 转换成求MST的问题呢? 相当于我们把特殊点扣出来, 然 ...
- GDOI2018 新的征程
看标题您一定以为考得很好.. Bad ending.想看美好结局的出门右转其他大佬博客. Day0 早上去车站的时候心情挺好.倒不是因为自己做足了准备,也不是因为预感到有好事发生,而是心情不好也没有用 ...
- [WC2015]未来程序(提交答案)
sub1:ans=a*b%c,龟速乘即可. #include <stdio.h> #include <stdlib.h> unsigned long long a, b, c, ...
随机推荐
- Dobble的学习视频地址
http://www.tebaidu.com/file-f698fb45eb1b5c59571936118968d86c89194311.html
- (1)安装----anaconda3下配置pyspark【单机】
1.确保已经安装jdk和anaconda3.[我安装的jdk为1.8,anaconda的python为3.6] 2.安装spark,到官网 http://spark.apache.org/downlo ...
- oracle中单引号的处理
当想让输出的结果中字段带有单引号', 场景一:连续三个单引号''' select '''helin''' from dual; ---'helin' 场景二:拼接字段的结果集--连续4个单引号 sel ...
- 关于libnmap 的一些应用
随笔描述 nmap 可以进行端口的扫描,在安全或运维中可以说是一款不错的神奇吧,在大部分LINUX 里面都自带了nmap 这款工具,他不仅仅是端口扫描,自身还提供许多插件可以使用. 官方文档 nmap ...
- 2019-02-25 SQL:cast(itemvalue as decimal(19,4))
1.Operand data type nvarchar(max) is invalid for sum operator 要转换格式 2.Conversion failed when convert ...
- sql where条件子句
where中可用的运算符: where 的执行 是从右到左: where的SQL优化:(where条件特别多的情况下,效果明显) 对于and,应该尽量把假的放到右边. 对于or,应该尽量把真的放到右边 ...
- sql 语句中的 (+) 是什么意思?
在select语句中(+)指的是外连接,是连接查询的一种方法.例:select t1.*,t2.* from dept t1,emp t2 where t1.deptno=t2.deptno(+);其 ...
- linux内核(三)文件系统
1.为什么需要根文件系统 (1)init进程的应用程序在根文件系统上(2)根文件系统提供了根目录/(3)内核启动后的应用层配置(etc目录)在根文件系统上.几乎可以认为:发行版=内核+rootfs(4 ...
- URAL 1517 Freedom of Choice
Freedom of Choice Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on Ural. Orig ...
- echarts 设置x轴的和y轴的属性
axisLabel:{ interval:0,//横轴信息全部显示 rotate:-30,//-30度角倾斜显示 } splitNumber:10