bzoj2143 飞飞侠 最短路

       用d[i][j][k]表示走到第(i,j)格,在不弹射的情况下还能再走k步的最小花费,那么有转移:

       d[i][j][k]->d[x][y][k-1],其中(i,j)和(x,y)相邻或相等,k>0,表示走到相邻一格或不走;

       d[i][j][0]+a[i][j]->d[x][y][b[i][j]],表示一次弹射。

       注意样例输入的A,B数组相反?另外听说卡spfa?

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define N 155
#define inf 1000000000
using namespace std;

const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int m,n,len,x1,x2,x3,y1,y2,y3,t1,t2,t3,a[N][N],b[N][N],d[N][N][N<<1];
bool vis[N][N][N<<1];
struct node{ int x,y,z,d; };
priority_queue<node> q;
bool operator <(node u,node v){ return u.d>v.d; }
void solve(int sx,int sy){
	int i,j,k; while (!q.empty()) q.pop();
	for (i=1; i<=m; i++)
		for (j=1; j<=n; j++)
			for (k=0; k<=len; k++){
				vis[i][j][k]=0; d[i][j][k]=inf;
			}
	d[sx][sy][0]=0;
	node u,v; u.x=sx; u.y=sy; u.z=u.d=0; q.push(u);
	while (!q.empty() && !(vis[x1][y1][0] && vis[x2][y2][0] && vis[x3][y3][0])){
		u=q.top(); q.pop();
		if (vis[u.x][u.y][u.z]) continue; vis[u.x][u.y][u.z]=1;
		if (u.z){
			for (k=0; k<4; k++){
				i=u.x+dx[k]; j=u.y+dy[k];
				if (i>0 && i<=m && j>0 && j<=n && u.d<d[i][j][u.z-1]){
					d[i][j][u.z-1]=v.d=u.d;
					v.x=i; v.y=j; v.z=u.z-1; q.push(v);
				}
			}
			v=u; v.z--;
			if (v.d<d[v.x][v.y][v.z]){ d[v.x][v.y][v.z]=v.d; q.push(v); }
		} else {
			v=u; v.z=a[v.x][v.y]; v.d+=b[v.x][v.y];
			if (v.d<d[v.x][v.y][v.z]){
				d[v.x][v.y][v.z]=v.d; q.push(v);
			}
		}
	}
}
int main(){
	scanf("%d%d",&m,&n); int i,j;
	for (i=1; i<=m; i++)
		for (j=1; j<=n; j++){
			scanf("%d",&a[i][j]); a[i][j]=min(a[i][j],max(i-1,m-i)+max(j-1,n-j)+1);
			len=max(len,a[i][j]);
		}
	for (i=1; i<=m; i++)
		for (j=1; j<=n; j++) scanf("%d",&b[i][j]);
	scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3);
	solve(x1,y1); t2+=d[x2][y2][0]; t3+=d[x3][y3][0];
	solve(x2,y2); t1+=d[x1][y1][0]; t3+=d[x3][y3][0];
	solve(x3,y3); t1+=d[x1][y1][0]; t2+=d[x2][y2][0];
	int ans=min(min(t1,t2),t3);
	if (ans<inf){
		puts((ans==t1)?"X":(ans==t2)?"Y":"Z");
		printf("%d\n",ans);
	} else puts("NO");
	return 0;
}


by lych

2016.3.4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值