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, ...
随机推荐
- SQLserver 导入超大CSV(100G以上)方法
1.似乎SQLSERVER2008对UTF8不兼容,采用SQLSERVER20052.采用SQLSERVER2005,还是出现UTF8诸如此类的问题,修改表结构,varchar改成 nvarchar3 ...
- [luogu4259 SCOI2003] 严格N元树 (高精 计数dp)
题目描述 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d(根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严格2元树有三个, ...
- 2019-03-28 SQL Server Pivot
--现在我们是用PIVOT函数将列[WEEK]的行值转换为列,并使用聚合函数Count(TotalPrice)来统计每一个Week列在转换前有多少行数据,语句如下所示 select * from Sh ...
- keil5下载程序时出现“internal command error”解决方法
今天下载的时候,插入下载器,查看Debug可用看到“internal command error”,一直找不到原因,后来查看上一个工程才发现,上一个程序禁用了Seral Wire 引脚,导致的. 解决 ...
- STM32 Cubemx 输出可调频率与占空比的PWM
这里就不对STM32的PWM进行讲解了,想要了解的可以百度一下,这里主要说怎么实现. 1.建立工程,我选的是STM32F103zet6芯片,选择定时器的PWM功能 2.配置时钟,我这里配的是内部时钟, ...
- 【codeforces 794C】Naming Company
[题目链接]:http://codeforces.com/contest/794/problem/C [题意] 有n个位置; 两个人; 每个人都有n个字符组成的集合s1,s2(可以有重复元素); 然后 ...
- Java String.replaceAll()方法
声明 以下是java.lang.String.replaceAll()方法的声明 public String replaceAll(String regex, String replacement) ...
- 2015 Multi-University Training Contest 5 hdu 5348 MZL's endless loop
MZL's endless loop Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Oth ...
- 数据库-mongodb-Gridfs
GridFS是一种将大型文件存储在MongoDB的文件规范: 数据库支持以BSON格式保存二进制对象. 但是MongoDB中BSON对象最大不能超过4MB. GridFS 规范提供了一种透明的机制,可 ...
- Android开发之AlarmManager具体解释
AlarmManager实质是一个全局的定时器,是Android中经常使用的一种系统级别的提示服务,在指定时间或周期性启动其他组件(包含Activity,Service,BroadcastReceiv ...