BZOJ2143 飞飞侠 & [校内NOIP2018模拟20181026] 最强大脑
Time Limit: 50 Sec Memory Limit: 259 MB
Description
飞飞国是一个传说中的国度,国家的居民叫做飞飞侠。飞飞国是一个N×M的矩形方阵,每个格子代表一个街区。然而飞飞国是没有交通工具的。飞飞侠完全靠地面的弹射装置来移动。每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。我们设第i行第j列的弹射装置有Aij的费用和Bij的弹
射能力。并规定有相邻边的格子间距离是\(1\)。那么,任何飞飞侠都只需要在(i,j)支付Aij的费用就可以任意选择弹
到距离不超过Bij的位置了。如下图
(从红色街区交费以后可以跳到周围的任意蓝色街区。)现在的问题很简单。有三个飞飞侠,分别叫做X,Y,Z。
现在它们决定聚在一起玩,于是想往其中一人的位置集合。告诉你3个飞飞侠的坐标,求往哪里集合大家需要花的
费用总和最低。
Input
输入的第一行包含两个整数\(N\)和\(M\),分别表示行数和列数。
接下来是2个N×M的自然数矩阵,为\(B_{i,j}\)和\(A_{i,j}\)
最后一行六个数,分别代表X,Y,Z所在地的行号和列号。
\(1\leq N,M\leq 150\);\(0\leq B_{i,j}\leq 10^9\);\(0\leq A_{i,j}\leq1000\)
Output
第一行输出一个字符X、Y或者Z。表示最优集合地点。
第二行输出一个整数,表示最小费用。如果无法集合,只输出一行NO
Sample Input
4 4
0 0 0 0
1 2 2 0
0 2 2 1
0 0 0 0
5 5 5 5
5 5 5 5
5 5 5 5
5 5 5 5
2 1 3 4 2 2
Sample Output
Z
15
Solution
嗯这道题的算法还是很有意思的,有时间还要再好好品味一下,真的是很新奇。
一眼最短路啊,但是如果我们直接跑Dijkstra的话(什么,这个世道你还敢用SPFA,更何况这还是网格图),转移数量太多了,肯定会T掉。
所以我们考虑一下转化,在一个点投射,相当于给了他一个\(B[i][j]\)的能量,然后每走一个消耗一个点数的能量。
那么我们设\(dist[i][j][k]\)表示走到\((i,j)\)这个点,还剩\(k\)点的能量的情况。那么转移就是这样的:
&dp[i][j][k]\rightarrow dp[x][y][k-1]\ \ |\ \ k>0,\text{$(x,y)$是与$(i,j)$香菱的点}\\
&dp[i][j][0]+a[i][j]\rightarrow dp[i][j][b[i][j]]\\
\end{align*}
\]
这样然后再加上Dijsktra的堆的复杂度就是\(O(n^3\log (n^3))\)的。比较卡常,在学校OJ上过不去,BZOJ上好像能过。
我们考虑优化。后面的学长们讨论了各种各样的优化,比如什么线段树优化建边,线段树进行转移,并查集优化最短路什么的。
但是这些我都不太会,所以只能自己YY出了一个实测效果很好的优化。显然Dijkstra里面每一次进行操作的点的\(dist\)值是单调不减的,所以如果遇到这样的情况我们可以直接跳过,不去转移:同一个点,如果已经操作过比现在这个状态能量要多的点,那么显然现在这个状态没有那个优,就可以不去转移了。我们只需要每次都转移那些能量大于曾经转移过的同一个点的能量值最大值的状态。这样的话,我们可以优化掉很多没有用的状态,实测效果不错,在BZOJ上排到了第二页,不过还是比不上那些神一样的并查集优化最短路。
但是遗憾的是,好像这样的复杂度还是没有变的,大家也许可以叉一叉。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
namespace io{
const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
inline void putc(char x){*oS++=x;if(oS==oT)flush();}
template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}
template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}
inline void print(const char *s){while(*s!='\0')putc(*s++);}
inline void scan(char *s){for(c=gc();c<=' ';c=gc());for(;c>' ';c=gc())*(s++)=c;*s='\0';}
struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::putc;using io::write;using io::print;
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}
const int N=150+3,INF=0x3f3f3f3f,fx[]={0,0,1,0,-1},fy[]={0,1,0,-1,0};
int n,m,b[N][N],a[N][N],dist[N][N][N<<1],vis[N][N],flag1,flag2,X1,Y1,X2,Y2,X3,Y3,ans=INF,get[4][4];char ans2;//错误笔记:get[4][4]开成了get[3][3]
struct Node{int x,y,en,dist;inline bool operator<(const Node&a)const{return dist>a.dist;}};priority_queue<Node>q;
inline void Dijkstra(Node S,Node T1,Node T2,int &flag1,int &flag2){
memset(dist,0x3f,sizeof(dist));memset(vis,-1,sizeof(vis));while(!q.empty())q.pop();
dist[S.x][S.y][b[S.x][S.y]]=a[S.x][S.y];q.push(Node{S.x,S.y,b[S.x][S.y],a[S.x][S.y]});flag1=flag2=0;
while(!q.empty()){
Node p=q.top();q.pop();if(vis[p.x][p.y]>=p.en)continue;int flag=(vis[p.x][p.y]==-1);SMAX(vis[p.x][p.y],p.en);
if(p.x==T1.x&&p.y==T1.y&&!flag1)flag1=p.dist;if(p.x==T2.x&&p.y==T2.y&&!flag2)flag2=p.dist;if(flag1&&flag2)return;
for(register int i=0;i<=4;++i){
Node f=Node{p.x+fx[i],p.y+fy[i],p.en-1,p.dist};if(f.x<1||f.x>n||f.y<1||f.y>m)continue;
if(vis[f.x][f.y]<=f.en&&dist[f.x][f.y][f.en]>p.dist){
dist[f.x][f.y][f.en]=dist[p.x][p.y][p.en];
q.push(f);
}
}
if(flag){Node f=Node{p.x,p.y,b[p.x][p.y],p.dist+a[p.x][p.y]};
if(vis[f.x][f.y]<=f.en&&dist[f.x][f.y][f.en]>p.dist+a[p.x][p.y]){
dist[f.x][f.y][f.en]=p.dist+a[p.x][p.y];
q.push(f);
}}
}if(!flag1)flag1=INF;if(!flag2)flag2=INF;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("zhber.in","r",stdin);freopen("zhber.out","w",stdout);
#endif
read(n),read(m);
for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(b[i][j]),SMIN(b[i][j],max(max(i-1+j-1,n-i+j-1),max(i-1+m-j,n-i+m-j)));
for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(a[i][j]);
read(X1),read(Y1),read(X2),read(Y2),read(X3),read(Y3);
Dijkstra(Node{X1,Y1},Node{X2,Y2},Node{X3,Y3},get[1][2],get[1][3]);
Dijkstra(Node{X2,Y2},Node{X1,Y1},Node{X3,Y3},get[2][1],get[2][3]);
Dijkstra(Node{X3,Y3},Node{X1,Y1},Node{X2,Y2},get[3][1],get[3][2]);
if(SMIN(ans,get[2][1]+get[3][1]))ans2='X';
if(SMIN(ans,get[1][2]+get[3][2]))ans2='Y';
if(SMIN(ans,get[1][3]+get[2][3]))ans2='Z';
if(ans2<'X')print("NO\n");else putc(ans2),putc('\n'),write(ans),putc('\n');
}
BZOJ2143 飞飞侠 & [校内NOIP2018模拟20181026] 最强大脑的更多相关文章
- BZOJ2143: 飞飞侠
2143: 飞飞侠 题意: 给出两个 n ∗ m 的矩阵 A,B,以及 3 个人的坐标 在 (i, j) 支付 Ai,j 的费用可以弹射到曼哈顿距离不超过 Bi,j 的位置 问三个人汇合所需要的最小总 ...
- 2018.11.05 bzoj2143: 飞飞侠(最短路)
传送门 最短路好题. 考虑对每个二维坐标建立一个高度属性. 这样每次如果在点(i,j,0)(i,j,0)(i,j,0)只能选择花费bi,jb_{i,j}bi,j跳向(i,j,ai,j)(i,j,a_ ...
- bzoj千题计划225:bzoj2143: 飞飞侠
http://www.lydsy.com/JudgeOnline/problem.php?id=2143 分层图最短路 把能够弹跳的曼哈顿距离看做能量 dp[i][j][k]表示在(i,j)位置,还有 ...
- [BZOJ2143]飞飞侠 并查集优化最短路
链接 题解 首先很容易想到对每个点暴力跑Dijkstra,但是这样边数是 \(N^4\) 的,考虑优化 发现每次松弛的时候,都要把整个地图扫一遍,每个节点都要重复扫很多次,如果我们在一个点不会再被更新 ...
- BZOJ3508 开灯 & [校内NOIP2018模拟20181027] 密码锁
Time Limit: 10 Sec Memory Limit: 128 MB Description xx作为信息学界的大神,拥有众多的粉丝.为了感谢众粉丝的爱戴,xx决定举办一场晚会.为了气派,x ...
- 刷题总结——飞飞侠(bzoj2143 最短路)
题目: Description 飞飞国是一个传说中的国度,国家的居民叫做飞飞侠.飞飞国是一个N×M的矩形方阵,每个格子代表一个街区.然而飞飞国是没有交通工具的.飞飞侠完全靠地面的弹射装置来移动.每个街 ...
- 【BZOJ 2143】 飞飞侠
Description 飞飞国是一个传说中的国度,国家的居民叫做飞飞侠.飞飞国是一个N×M的矩形方阵,每个格子代表一个街区.然而飞飞国是没有交通工具的.飞飞侠完全靠地面的弹射装置来移动.每个街区都装有 ...
- BZOJ 2143 飞飞侠(分层最短路)
飞飞国是一个N×M的矩形方阵,每个格子代表一个街区.然而飞飞国是没有交通工具的.飞飞侠完全靠地面的弹射装置来移动.每个街区都装有弹射装置.使用弹射装置是需要支付一定费用的.而且每个弹射装置都有自己的弹 ...
- [NOIP2018模拟赛10.16]手残报告
[NOIP2018模拟赛10.16]手残报告 闲扯 炉石乱斗模式美滋滋啊,又颓到好晚... 上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了 ...
随机推荐
- 【转】通过Nginx部署Django
https://www.cnblogs.com/frchen/p/5709533.html Django的部署可以有很多方式,采用nginx+uwsgi的方式是其中比较常见的一种方式. 在这种方式中, ...
- 575 div 3 C. Robot Breakout
C. Robot Breakout 题目大意: 一堆机器人,已知他们的初始位置(x,y),本来都可以向四个方向移动,但是一些原因,一个机器人的不能向某些方向移动,该方向能移动用1表示,否则用0 求他们 ...
- 转载:TypeError: Cannot read property 'compilation' of undefined vue 打包运行npm run build 报错
转载自:https://www.jianshu.com/p/3f8f60e01797 运行npm run build打包时,报错如下: 我的package.json如下: { ... " ...
- PHP操作Excel – PHPExcel 基本用法
利用PHP实现对于Excel的写入和读取,主要借助于PHPExcel插件来完成. 准备工作: 1.下载PHPExcel的SDK,下载地址:https://github.com/PHPOffice/PH ...
- P1541乌龟棋
传送 这题咋做? 当然是爆搜了. 但是蒟蒻不会爆搜(TLE,WA两开花qwq),更不会记忆化搜索,所以我们换个思路. 注意这句话: 这肯定是有用的(洛咕还不会闲圈到给一句毛用都没有的话),那它有什么用 ...
- 125、TensorFlow计算图的执行
# TensorFlow使用tf.Session类来表示客户端程序之间的链接 # 虽然一个在其他语言中相似的接口也是可以使用的,列如C++ runtime # 一个tf.Session对象提供了访问本 ...
- Oracle查询中文乱码
1.查询Oracle服务端字符集 SQL> select userenv('language') from dual ; USERENV('LANGUAGE') ---------------- ...
- 为什么每次打出的包都是Release版本呢?
参考了:xcodebuild命令 https://www.cnblogs.com/liuluoxing/p/8622108.html 重新打个包,验证一下想法
- jmeter之2种方法录制脚本
有时候候录制脚本比写脚本且快,这时候我们可以采用录制的方法完成jmeter脚本工作 目录 1.badboy录制 2.代理服务器录制 1.badboy录制 第一步:下载安装 badboy2.2下载:链接 ...
- 利用Fiddler对手机应用抓包
1.启动Fiddler,打开菜单栏中的 Tools > Fiddler Options,打开“Fiddler Options”对话框. 2.在Fiddler Options”对话框切换到“Con ...