【NOIP模拟】 (10.31) T2 朋友

24 篇文章 0 订阅
8 篇文章 0 订阅

朋友

Source:BZOJ 2143 飞飞侠
题目描述:
       飞飞国是一个传说中的国度,国家的居民叫做飞飞侠。飞飞国是一个N×M的矩形方阵,每个格子代表一个街区。然而飞飞国是没有交通工具的。飞飞侠完全靠地面的弹射装置来移动。每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。我们设第i行第j列的弹射装置有Aij的费用和Bij的弹射能力。并规定有相邻边的格子间距离是1。那么,任何飞飞侠都只需要在(i,j)支付Bij的费用就可以任意选择弹到曼哈顿距离不超过Aij的位置了。如下图 

(从红色街区交费以后可以跳到周围的任意蓝色街区。) 现在的问题很简单。有三个飞飞侠,分别叫做X,Y,Z。现在它们决定聚在一起玩,于是想往其中一人的位置集合。告诉你3个飞飞侠的坐标,求往哪里集合大家需要花的费用总和最低。
输入格式:
       输入的第一行包含两个整数N和M,分别表示行数和列数。接下来是2个N×M的自然数矩阵,为Aij和Bij 最后一行六个数,分别代表X,Y,Z所在地的行号和列号。
输出格式:
       第一行输出一个字符X、Y或者Z。表示最优集合地点。第二行输出一个整数,表示最小费用。如果无法集合,只输出一行NO
输据范围:
       对于20%的数据:N,M<=10;Bi,j<=20
       对于50%的输据:N,M<=100;Bi,j<=20
       对于100%的数据:1< =N,M<=150;0<=Aij<=10^9;0<=Bij<=1000

解析:
       对于20%的数据,从u可以弹到v那么建一条从u到v,长度为u点弹射费用的边,然后从X,Y,Z三个点分别开始做单源最短路。乐意用Bellmax-Ford,Dijkstra,SPFA。
       期望得分:20分。
       对于50%的数据,我们可以对20%的Dijkstra进行优化。
       优化一:建邻接表。
       优化二:一旦另外两个点的最短路已经算出,立刻终止Dijkstra
       期望得分:50分。
       对于100%的数据,由于边的数量过于巨大,直接建边会RE(不过hyj大佬神奇地AC了),于是我们考虑一种特殊的建边方法。令dis[i][j][k]为到坐标为(i,j)高度为k点的最短路。解释一下这个高度,我们可以将每一个弹射点高度设为0,它能达到的高度即为它的弹射能力的大小。以这个点为中心能向四个方向运动,每向一个方向移动一格高度减一,当高度为零时说明不能再继续走了,这时如果这个位置也有一个弹射器,我们就又可以弹射到A[i][j]的高度,然后重复这个操作。于是我们就可以将这个中心点到周围四个点建四条权值为0的有向边,将高度为0的点到这个点的弹射的高度的位置建一条权值为B[i][j]的有向边,用这种方法建边边数是直接建边的1/N,这是用刚才的优化加上Dijkstra的堆优化便完全没有问题了。
       注意!点的移动不一定必须向四周移动,也可以原地不动,只是高度变低。

代码(50分暴力)
#include <bits/stdc++.h>
using namespace std;

const int Max=5001000;
long long n,m,s,tot;
long long a[210][210],b[210][210];
long long first[Max],dis[Max];
struct shu{long long to,next,len;};
shu bian[Max];
struct dian{long long x,y;};
dian d[5];
long long dian[210][210];

inline int get_int()
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();}
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}

inline void build(int x,int y,int z)
{
   s++;
   bian[s].next=first[x];
   first[x]=s;
   bian[s].to=y;
   bian[s].len=z;
}

inline void pre()
{
   for(register int i=1;i<=n;i++)
     for(register int j=1;j<=m;j++)
       for(register int k=i-a[i][j];k<=i+a[i][j];k++)
         for(register int t=j-a[i][j];t<=j+a[i][j];t++)
           if((abs(i-k)+abs(j-t))<=a[i][j]&&k>=1&k<=n&&t>=1&&t<=m&&(k!=i||t!=j)) build(dian[i][j],dian[k][t],b[i][j]);
}

inline void dijkstra(int s,int x,int y)
{
   priority_queue<pair<long long,int> >q;
   memset(dis,127,sizeof(dis));
   dis[s]=0;
   q.push(make_pair(0,s));
   int t=0;
   while(!q.empty())
   {
   	 int point=q.top().second;
   	 if(point==x||point==y) t++;
   	 if(t==2) return;
   	 q.pop();
   	 for(int u=first[point];u;u=bian[u].next)
   	 {
   	   if(dis[point]+bian[u].len<dis[bian[u].to])
   	   {
   	   	 dis[bian[u].to]=dis[point]+bian[u].len;
   	   	 q.push(make_pair(-dis[bian[u].to],bian[u].to));
   	   }
   	 }
   }
}

int main()
{
  // freopen("friend.in","r",stdin);
   //freopen("lx.out","w",stdout);

   n=get_int();
   m=get_int();
   for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
       dian[i][j]=++tot;
   for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
       a[i][j]=get_int();
   for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
       b[i][j]=get_int();
   d[1].x=get_int();
   d[1].y=get_int();
   d[2].x=get_int();
   d[2].y=get_int();
   d[3].x=get_int();
   d[3].y=get_int();

   pre();

   //for(int u=first[6];u;u=bian[u].next) cout<<bian[u].len<<" ";
  // return 0; 

   long long minn=1e18,ans=0,len1=0,len2=0,len3=0;
   dijkstra(dian[d[1].x][d[1].y],2,3);
   len2+=dis[dian[d[2].x][d[2].y]];
   len3+=dis[dian[d[3].x][d[3].y]];
   dijkstra(dian[d[2].x][d[2].y],1,3);
   len1+=dis[dian[d[1].x][d[1].y]];
   len3+=dis[dian[d[3].x][d[3].y]];
   dijkstra(dian[d[3].x][d[3].y],1,2);
   len1+=dis[dian[d[1].x][d[1].y]];
   len2+=dis[dian[d[2].x][d[2].y]];

   if(minn>=len3) {minn=len3;ans=3;}
   if(minn>=len2) {minn=len2;ans=2;}
   if(minn>=len1) {minn=len1;ans=1;}

   if(minn==1e19) {cout<<"NO\n";return 0;}
   if(ans==1) cout<<"X\n"<<minn;
   else
     if(ans==2) cout<<"Y\n"<<minn;
       else if(ans==3) cout<<"Z\n"<<minn;

   return 0;
}

代码(100分标算):
#include <iostream> 
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <queue>
#include <ctime>
using namespace std;

const int fx[5]={0,1,-1,0,0};
const int fy[5]={0,0,0,1,-1};
const int Max=10010000;
long long n,m,sum,ans,top;
long long X1,Y1,X2,Y2,X3,Y3;
long long dis[210][210][410];
long long a[210][210],b[210][210];
long long exist[210][210][410];
struct dian{int x,y,h;long long dis;};
dian now;

inline int get_int()
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();}
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}

inline bool operator < (const dian &a,const dian &b)   //小根堆
{
   return a.dis>b.dis;
}

inline void dijkstra(int x,int y)      //Dijkstra跑最短路
{
   priority_queue<dian>q;
   memset(exist,0,sizeof(exist));
   for(register int i=1;i<=n;i++)
     for(register int j=1;j<=m;j++)
       for(register int k=0;k<=top;k++) dis[i][j][k]=1e18;//不用memset的原因是memset是int级别的
   now.x=x;
   now.y=y;
   now.h=0;
   now.dis=0;
   dis[x][y][0]=0;
   q.push(now);
   while(!q.empty())
   {
   	 now=q.top();
   	 q.pop();
   	 if(exist[now.x][now.y][now.h]) continue;
   	 if(exist[X1][Y1][0]+exist[X2][Y2][0]+exist[X3][Y3][0]==3) return;
   	 exist[now.x][now.y][now.h]=1;
   	 if(now.h>0)
   	 {
   	   for(int i=0;i<=4;i++)
   	   {
   	     if((!exist[now.x+fx[i]][now.y+fy[i]][now.h-1])&&(now.x+fx[i]>=1)&&(now.x+fx[i]<=n)&&(now.y+fy[i]>=1)&&(now.y+fy[i]<=m))
   	     {
   	       int xx=now.x+fx[i],yy=now.y+fy[i];
   	       if(dis[xx][yy][now.h-1]>dis[now.x][now.y][now.h])
   	       {
   	       	 dis[xx][yy][now.h-1]=dis[now.x][now.y][now.h];
   	       	 q.push((dian){xx,yy,now.h-1,dis[xx][yy][now.h-1]});
   	       }
   	     }
   	   }
   	 }
   	 else
   	 {
   	   if(!exist[now.x][now.y][a[now.x][now.y]])
   	   {
   	   	 if(dis[now.x][now.y][a[now.x][now.y]]>dis[now.x][now.y][0]+b[now.x][now.y])
   	   	 {
   	   	 	dis[now.x][now.y][a[now.x][now.y]]=dis[now.x][now.y][0]+b[now.x][now.y];
   	   	 	q.push((dian){now.x,now.y,a[now.x][now.y],dis[now.x][now.y][a[now.x][now.y]]});
   	   	 }
   	   }
   	 }
   }
}

int main()
{
  // freopen("friend.in","r",stdin);
   //freopen("friend.out","w",stdout);

   n=get_int();
   m=get_int();
   for(register int i=1;i<=n;i++)
     for(register int j=1;j<=m;j++)
     {
       a[i][j]=get_int();
       a[i][j]=min(a[i][j],n+m-2);      //曼哈顿距离最多为n+m-2
       top=max(a[i][j],top);
     }
   for(register int i=1;i<=n;i++)
     for(register int j=1;j<=m;j++)
       b[i][j]=get_int();
   X1=get_int();
   Y1=get_int();
   X2=get_int();
   Y2=get_int();
   X3=get_int();
   Y3=get_int();

   long long minn=1e18,len1=0,len2=0,len3=0;
   dijkstra(X1,Y1);
   len2+=dis[X2][Y2][0];
   len3+=dis[X3][Y3][0];
   dijkstra(X2,Y2);
   len1+=dis[X1][Y1][0];
   len3+=dis[X3][Y3][0];
   dijkstra(X3,Y3);
   len1+=dis[X1][Y1][0];
   len2+=dis[X2][Y2][0];

   if(minn>=len3) {minn=len3;ans=3;}
   if(minn>=len2) {minn=len2;ans=2;}
   if(minn>=len1) {minn=len1;ans=1;}

   if(minn==1e18) {cout<<"NO\n";return 0;}
   if(ans==1) cout<<"X\n"<<minn;
   else
     if(ans==2) cout<<"Y\n"<<minn;
       else if(ans==3) cout<<"Z\n"<<minn;

   return 0;
}

代码(暴力建边100分Orz)
#include <bits/stdc++.h>
using namespace std;
inline void R (int &v) {
	static char ch;
	v = 0;
	bool p = 0;
	do{
		ch = getchar();
		if(ch=='-') p = 1;
	} while(!isdigit(ch));
	while(isdigit(ch)) {
		v = (v + (v << 2) << 1) + (ch^'0');
		ch = getchar();
	}
	if(p) v=-v;
}
int n, m, m1;
inline int calc(int x, int y) {
	return (x - 1) * m1 + y;
}
int a[42505], b[42505];
long long dis[42505];
int X, Y, Z;
bool vis[42505];
#define mk make_pair
priority_queue<pair<long long, int>, vector<pair<long long, int> >, greater<pair<long long, int> > > q1, q2, q3;
long long d[5][5];
int main() {
//	freopen("friend.in","r",stdin);
//	freopen("friend.out","w",stdout);
	R(n), R(m);
	m1 = m + 1;
	for(register int i = 1; i <= n; ++i) {
		for(register int j = 1; j <= m; ++j) {
			R(a[calc(i, j)]);
		}
	}
	for(register int i = 1; i <= n; ++i) {
		for(register int j = 1; j <= m; ++j) {
			R(b[calc(i, j)]);
		}
	}
	int x, y;
	R(x), R(y);
	X = calc(x, y);
	R(x) ,R(y);
	Y = calc(x, y);
	R(x), R(y);
	Z = calc(x, y);
	int max1;
	memset(dis, 0x01, sizeof(dis));
	dis[X] = 0;
	q1.push(mk(0, X));
	int t, ju, temp, may, v, co;
	while(!q1.empty()) {
		do{
			t = q1.top().second;
			q1.pop();
		}while(vis[t]);
		vis[t] = 1;
		if(vis[Y] && vis[Z]) break;
		x = t / m1 + 1;
		y = t - (x - 1) * m1;
		ju = a[calc(x, y)];
		co = b[calc(x, y)];
		max1 = min(n, x + ju);
		for(register int nowx = max(1, x - ju); nowx <= max1; ++nowx) {
			temp = abs(nowx - x);
			may = min(m, y + ju - temp);
			for(register int nowy = max(1, y - ju + temp); nowy <= may; ++nowy) {
				v = calc(nowx, nowy);
				if(dis[v] > dis[t] + co){
					dis[v] = dis[t] + co;
					q1.push(mk(dis[v], v));
				}
			}
		}
	}
	d[1][2] = dis[Y], d[1][3] = dis[Z];
	memset(dis, 0x01, sizeof(dis));
	dis[Y] = 0;
	memset(vis, 0, sizeof(vis));
	q2.push(mk(0, Y));
	while(!q2.empty()) {
		do{
			t = q2.top().second;
			q2.pop();
		}while(vis[t]);
		vis[t] = 1;
		if(vis[X] && vis[Z]) break;
		x = t / m1 + 1;
		y = t - (x - 1) * m1;
		ju = a[calc(x, y)];
		co = b[calc(x, y)];
		max1 = min(n, x + ju);
		for(register int nowx = max(1, x - ju); nowx <= max1; ++nowx) {
			temp = abs(nowx - x);
			may = min(m, y + ju - temp);
			for(register int nowy = max(1, y - ju + temp); nowy <= may; ++nowy) {
				v = calc(nowx, nowy);
				if(dis[v] > dis[t] + co){
					dis[v] = dis[t] + co;
					q2.push(mk(dis[v], v));
				}
			}
		}
	}
	d[2][1] = dis[X], d[2][3] = dis[Z];
	memset(dis, 0x01, sizeof(dis));
	dis[Z] = 0;
	memset(vis, 0, sizeof(vis));
	q3.push(mk(0, Z));
	while(!q3.empty()) {
		do{
			t = q3.top().second;
			q3.pop();
		}while(vis[t]);
		vis[t] = 1;
		if(vis[Y] && vis[X]) break;
		x = t / m1 + 1;
		y = t - (x - 1) * m1;
		ju = a[calc(x, y)];
		co = b[calc(x, y)];
		max1 = min(n, x + ju);
		for(register int nowx = max(1, x - ju); nowx <= max1; ++nowx) {
			temp = abs(nowx - x);
			may = min(m, y + ju - temp);
			for(register int nowy = max(1, y - ju + temp); nowy <= may; ++nowy) {
				v = calc(nowx, nowy);
				if(dis[v] > dis[t] + co){
					dis[v] = dis[t] + co;
					q3.push(mk(dis[v], v));
				}
			}
		}
	}
	d[3][1] = dis[X], d[3][2] = dis[Y];
	if(d[2][1] + d[3][1] >= 1000000000000000ll && d[3][2] + d[1][2] >= 1000000000000000ll && d[2][3] + d[1][3] >= 1000000000000000ll) {
		puts("NO");
		return 0;
	}
	if(d[2][1] + d[3][1] <= d[3][2] + d[1][2] &&  d[2][1] + d[3][1] <= d[2][3] + d[1][3]) {
		puts("X");
		cout<<d[2][1] + d[3][1];
		return 0;
	} else {
		if(d[3][2] + d[1][2] <= d[2][1] + d[3][1] &&  d[3][2] + d[1][2] <= d[2][3] + d[1][3]) {
			puts("Y");
			cout<<d[3][2] + d[1][2];
			return 0;
		} else {
			if(d[2][3] + d[1][3] <= d[2][1] + d[3][1] &&  d[2][3] + d[1][3] <= d[3][2] + d[1][2]) {
				puts("Z");
				cout<<d[2][3] + d[1][3];
				return 0;
			}
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值