7月11日小学期记录

题目描述

作物杂交是作物栽培中重要的一步。已知有 N 种作物 (编号 1 至 N ),第 i 种作物从播种到成熟的时间为 Ti​。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 N 种作物中的一种。
初始时,拥有其中 M 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。
如存在 4 种作物 ABCD,各自的成熟时间为 5 天、7 天、3 天、8 天。初始拥有 AB 两种作物的种子,目标种子为 D,已知杂交情况为 A × B → C,A × C → D。则最短的杂交过程为:
第 1 天到第 7 天 (作物 B 的时间),A × B → C。
第 8 天到第 12 天 (作物 A 的时间),A × C → D。
花费 12 天得到作物 D 的种子。

输入描述

输入的第 1 行包含 4 个整数 N, M, K, T ,N 表示作物种类总数 (编号 1 至 N ),M 表示初始拥有的作物种子类型数量,K 表示可以杂交的方案数,T 表示目标种子的编号。
第 2 行包含 N 个整数,其中第 ii 个整数表示第 ii 种作物的种植时间 Ti​ (1≤Ti​≤100)。
第 3 行包含 M 个整数,分别表示已拥有的种子类型 Kj​ (1≤Kj​≤M), Kj​ 两两不同。
第 4 至 K + 3 行,每行包含 3 个整数 A, B,C 表示第 A 类作物和第 B 类作物杂交可以获得第 C 类作物的种子。
其中, 1≤N≤2000,2≤M≤N,1≤K≤105,1≤T≤N, 保证目标种子一定可以通过杂交得到。

输出描述

输出一个整数,表示得到目标种子的最短杂交时间。

输入输出样例

示例
输入
6 2 4 6
5 3 4 6 4 9
1 2
1 2 3
1 3 4
2 3 5
4 5 6

输出
16

样例说明

第 1 天至第 5 天,将编号 1 与编号 2 的作物杂交,得到编号 3 的作物种子。
第 6 天至第 10 天,将编号 1 与编号 3 的作物杂交,得到编号 4 的作物种子。
第 6 天至第 9 天,将编号 2 与编号 3 的作物杂交,得到编号 5 的作物种子。
第 11 天至第 16 天,将编号 4 与编号 5 的作物杂交,得到编号 6 的作物种子。
总共花费 16 天。

运行限制

最大运行时间:2s
最大运行内存: 256M

解析

1,此题数据范围不大,所以,我就是简单的暴力模拟求解,使用迪杰斯特拉算法的贪心思想。此题实际就是求一个最短路径的问题。
2 变量定义n,m,k,t,就是题目中的含义;
times[n+1],ok[n+1],finished[n+1],
times[i]存农作物i生长时间,ok[i]存得到农作物i的时间,finished[i]是bool标记,为0表示农作物i还未找到获得它的最短时间,为1表示农作物i 找到最短时间。
K[k]存杂交方案,K[i][0]、K[i][1]存父母物种,K[i][2]存获得物种。
3,初始时,已有物种ok[i]=0 finished[i]=1,其余ok[i]=-1 finished[i]=0

for(i=0;i<k;i++)
{
   if(ok[K[i][0]]==-1) continue;
   if(ok[K[i][1]]==-1) continue;
   if(finished[K[i][2]] ) continue;
   int max1=times[K[i][1]]>times[K[i][0]]?times[K[i][1]]:times[K[i][0]];
   int max2=ok[K[i][1]]>ok[K[i][0]]?ok[K[i][1]]:ok[K[i][0]];
   if(ok[K[i][2]]==-1||max1+max2<ok[K[i][2]]) 
	 ok[K[i][2]]=max1+max2;
}

上面的for循环模拟杂交,显然ok[K[i][0]]-1或ok[K[i][1]]-1表示父母物种不存在,暂时无法使用此方案;如果finished[K[i][2]] 1,表示获得物种已经找到最短时间,就不必再次使用此方案了;max1是杂交需要的时间,max2是此次杂交最早开始时间。显然,ok[K[i][2]]-1时,表示获得物种原来不存在,
ok[K[i][2]]=max1+max2,或者,按照此方案获得的时间更少max1+max2<ok[K[i][2]],也要更新
ok[K[i][2]]=max1+max2。
5 ,上面的for结束后,要找到本轮杂交过后还未确定最短时间的所获得物种中,拥有最短的那个时间物种,并设finished标记为1,
6,整体finished[t]=1,就找到答案了。

#include<stdio.h>
#include<math.h>
 
 
int main()
{  
     int  n,m,k,t;
     scanf("%d%d%d%d",&n,&m,&k,&t);
     int times[n+1],ok[n+1],finished[n+1];
     int i;
     for(i=1;i<=n;i++)
       scanf("%d",&times[i]);
     memset(ok,-1,sizeof(int)*(n+1));
     memset(finished,0,sizeof(int)*(n+1));
     for(i=1;i<=m;i++)
     {
     	int tmp;
     	scanf("%d",&tmp);
     	ok[tmp]=0;
     	finished[tmp]=1; 
	 }
	 int K[k][3];
	 for(i=0;i<k;i++)
	   scanf("%d%d%d",&K[i][0],&K[i][1],&K[i][2]) ;
	   
	 while(!finished[t]  )
	 {  
	     for(i=0;i<k;i++)
	 	 {
	 	 	if(ok[K[i][0]]==-1) continue;
	 	 	if(ok[K[i][1]]==-1) continue;
	 	 	if(finished[K[i][2]] ) continue;
	 	 	int max1=times[K[i][1]]>times[K[i][0]]?times[K[i][1]]:times[K[i][0]];
	 	 	int max2=ok[K[i][1]]>ok[K[i][0]]?ok[K[i][1]]:ok[K[i][0]];
	 	 	if(ok[K[i][2]]==-1||max1+max2<ok[K[i][2]])
			    ok[K[i][2]]=max1+max2;
		 }       
		 int min=0;
		 for(i=1;i<n+1;i++)
		    if(!finished[i] && ok[i]!=-1 && (!min||ok[i]<ok[min]))
		         min=i;
	    finished[min]=1;
	  } 
	  printf("%d",ok[t]);
    
 
    return 0;
}

题目描述

小蓝在 L 市开出租车。
L 市的规划很规整,所有的路都是正东西向或者正南北向的,道路都可以看成直线段。东西向的道路互相平行,南北向的道路互相平行,任何一条东西向道路垂直于任何一条南北向道路。
从北到南一共有 n条东西向道路,依次标号为H1​,H2​,⋅⋅⋅,Hn​。从西到东一共有 m 条南北向的道路,依次标号为 S1​,S2​,⋅⋅⋅,Sm​。
每条道路都有足够长,每一条东西向道路和每一条南北向道路都相交, Hi​ 与 Sj​ 的交叉路口记为 (i,j)。
从 H1​ 和 S1​ 的交叉路口 (1,1) 开始,向南遇到的路口与 (1,1) 的距离分别是h1​,h2​,⋅⋅⋅,hn−1​,向东遇到路口与 (1,1) 的距离分别是 w1​,w2​,⋅⋅⋅,wm−1​。
道路的每个路口都有一个红绿灯。
时刻 0 的时候,南北向绿灯亮,东西向红灯亮,南北向的绿灯会持续一段时间(每个路口不同),然后南北向变成红灯,东西向变成绿灯,持续一段时间后,再变成南北向绿灯,东西向红灯。
已知路口 (i,j) 的南北向绿灯每次持续的时间为gi,j​,东西向的绿灯每次持续的时间为ri,j​,红绿灯的变换时间忽略。
当一辆车走到路口时,如果是绿灯,可以直行、左转或右转。如果是红灯,可以右转,不能直行或左转。如果到路口的时候刚好由红灯变为绿灯,则视为看到绿灯,如果刚好由绿灯变为红灯,则视为看到红灯。
每段道路都是双向道路,道路中间有隔离栏杆,在道路中间不能掉头,只能在红绿灯路口掉头。掉头时不管是红灯还是绿灯都可以直接掉头。掉头的时间可以忽略。
小蓝时刻 0从家出发。今天,他接到了 q 个预约的订单,他打算按照订单的顺序依次完成这些订单,就回家休息。中途小蓝不准备再拉其他乘客。
小蓝的家在两个路口的中点,小蓝喜欢用 x1​,y1​,x2​,y2​ 来表示自己家的位置,即路口 (x1​,y1​) 到路口 (x2​,y2​) 之间的道路中点的右侧,保证两个路口相邻中间没有其他路口)。请注意当两个路口交换位置时,表达的是路的不同两边,路中间有栏杆,因此这两个位置实际要走比较远才能到达。
小蓝的订单也是从某两个路口间的中点出发,到某两个路口间的中点结束。小蓝必须按照给定的顺序处理订单,而且一个时刻只能处理一个订单,不能图省时间而同时接两位乘客,也不能插队完成后面的订单。
小蓝只对 L 市比较熟,因此他只会在给定的n 条东西向道路和m 条南北向道路上行驶,而且不会驶出H1​,Hn​,S1​,Sm​ 这几条道路所确定的矩形区域(可以到边界)。
小蓝行车速度一直为 1,乘客上下车的时间忽略不计。
请问,小蓝最早什么时候能完成所有订单回到家。

输入描述

输入第一行包含两个整数 n,m,表示东西向道路的数量和南北向道路的数 量。
第二行包含n−1 个整数 h1​,h2​,⋅⋅⋅,hn−1​。
第三行包含m−1 个整数 w1​,w2​,⋅⋅⋅,wm−1​。
接下来 n 行,每行 m 个整数,描述每个路口南北向绿灯的时间,其中的第 i行第 j 列表示 gi,j​。
接下来 n行,每行 m个整数,描述每个路口东西向绿灯的时间,其中的第 i行第 j列表示rij​。
接下来一行包含四个整数x1​,y1​,x2​,y2​,表示小蓝家的位置在路口 (x1​,y1​) 到路口 (x2​,y2​) 之间的道路中点的右侧。
接下来一行包含一个整数 q,表示订单数量。
接下来 q 行,每行描述一个订单,其中第 ii 行包含八个整数xi1​,yi1​,xi2​,yi2​, xi3​,yi3​,xi4​,yi4​,表示第 i个订单的起点为路口 (xi1​,yi1​) 到路口 (xi2​,yi2​) 之间的道路中点的右侧,第 i个订单的终点为路口 (xi3​,yi3​) 到路口 (xi4​,yi4​) 之间的道路中 点的右侧。
其中有 , (1≤n,m≤100,1≤q≤30,1≤h1​<h2​<⋅⋅⋅<hn−1​≤105,1≤w1​<w2​<⋅⋅⋅<wm−1​≤105,1≤gi,j​≤1000,1≤rij​≤1000(,给定的路口一定合法。

输出描述

输出一个实数,表示小蓝完成所有订单最后回到家的最早时刻。四舍五入保留一位小数

输入输出样例

示例
输入
2 3
200
100 400
10 20 10
20 40 30
20 20 20
20 20 20
2 1 1 1
1
2 2 1 2 1 2 1 3

输出
1620.0

运行限制

最大运行时间:1s
最大运行内存: 128M

解析

1,此题目,不要被其“困难”的难度等级吓到,实际很简单,但却非常费事,迪杰斯特拉便可求解,我的代码中的迪杰斯特拉加上了堆优化,为了方面我直接使用了C++中的优先队列(堆)。如果大家看代码,会发现,我的代码除了用到优先队列的地方,其他全是C风格的。
2,在你充分理解题目意思后,再开始看下面文字
3,题目中城市的地图如上所示,代码中的变量定义基本上使用了题目中的变量,下面会逐步解析我的代码。
4,n是行数,m是列数

int n,m;  

5,h数组存南北方向路的长度,有效下标范围1—n-1;w数组存东西方向路的长度,有效下标范围1—m-1。

int h[105],w[105];

6,g数组存放路口南北向绿灯持续时间,也是东西向红灯的持续时间。r数组存放路口南北向红灯持续时间,也是东西向绿灯的持续时间。这两个数组的有效下标范围都是[x∈1—n][y∈1----m],x是行号,y是列号。

int g[105][105],r[105][105];

7, 从主函数开始看
scanf(“%d%d”,&n,&m);
读入n和m
for(i=1;i<=n-1;i++)
scanf(“%d”,&h[i]);
for(i=n-1;i>=2;i–)
h[i]-=h[i-1];
注意:题目给出的道路长度是距离第一个路口的绝对长度,这里求一下差分,就会得到每段路的长度。
for(i=1;i<=m-1;i++)
scanf(“%d”,&w[i]);
for(i=m-1;i>=2;i–)
w[i]-=w[i-1];
注意:题目给出的道路长度是距离第一个路口的绝对长度,这里求一下差分,就会得到每段路的长度。

	for(i=1;i<=n;i++)
	  for(j=1;j<=m;j++)
	     scanf("%d",&g[i][j]);
	for(i=1;i<=n;i++)
	  for(j=1;j<=m;j++)
	     scanf("%d",&r[i][j]);

读取红绿灯时间。
8,接下来变量 x1,y1,x2,y2是小蓝家的位置。tx1,ty1,tx2,ty2是x1,y1,x2,y2的备份,一会有用。

int x1,y1,x2,y2,tx1,ty1,tx2,ty2;
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	tx1=x1,ty1=y1,tx2=x2,ty2=y2;

变量q是订单的数量,re存放答案,初始为零。变量xi1,yi1,xi2,yi2,xi3,yi3,xi4,yi4存放订单的起点和终点。

int q;
	double re=0;
	scanf("%d",&q);
	int xi1,yi1,xi2,yi2,xi3,yi3,xi4,yi4;

9,接下来

while(q--)//循环q次
	{
		scanf("%d%d%d%d",&xi1,&yi1,&xi2,&yi2); //读订单的起点
		re+=dj(x1,y1,x2,y2,xi1,yi1,xi2,yi2,re);
    .//函数dj就是迪杰斯特拉算法计算路径,参数x1,y1,x2,y2表示出发地,xi1,yi1,xi2,yi2表示目的地,参数re是当前积累的时间。这里假设刚刚开始,re=0,x1,y1,x2,y2表示出发地是小蓝家,目的地是第一单的起点;显然这里dj计算的是小蓝家到第一单接乘客的地方,需要的时间。dj的返回值需要累加到re,才能体现时间流逝。
		//printf("%fre\n",re);
		scanf("%d%d%d%d",&xi3,&yi3,&xi4,&yi4);
     //读订单的终点
		re+=dj(xi1,yi1,xi2,yi2,xi3,yi3,xi4,yi4,re);
这次的dj计算这个订单需要的时间。
		x1=xi3,y1=yi3,x2=xi4,y2=yi4;
    //把刚刚结束订单的终点设为出发地后,进入下一轮循环
	}
	re+=dj(xi3,yi3,xi4,yi4,tx1,ty1,tx2,ty2,re);
//最后,这是计算最后一单终点到回家的时间。
	printf("%.1f\n",re);

10,再看函数

double dj(int x1,int y1,int x2,int y2, int x3,int y3,int x4,int y4,double t)

原型中,参数x1,y1,x2,y2表示出发地点。参数x3,y3,x4,y4表示目的地,参数t表示此轮函数开始时的时间起点,这个用于算红绿灯时间的。
注意,此题目时间和距离单位相同,所以不加区分。另外,迪杰斯特拉求最短路径,数据结构书上说,应该有个“有向图”,要么邻接矩阵表示“有向图”,要么邻接表表示“有向图”。但,这里没有邻接矩阵,也没有邻接表。这个“有向图”是隐含的,“有向图”的顶点不是路口而是道路中间的右侧,即题目中“上下人”的地方,实际上x1,y1,x2,y2就表示一个顶点。有了顶点后,每个顶点最多发射4条边,到另外4个顶点,例如下图中,从
A调头可达B,从A右转可达C,从A直行可达D,从A左转可达E。如果A表示为(x1,y1,x2,y2),那么B为(x2,y2,x1,y1),C为(x2,y2,x2+1,y2),D为(x2,y2,x2,y2+1),E为(x2,y2,x2-1,y2)
11,接下来

int flag[2*(n*(m-1)+(n-1)*m)];
	double dist[2*(n*(m-1)+(n-1)*m)];

这两个数组,flag存放每个隐含的“有向图“顶点是否已经求得最短路径,dist记录从出发地到当前顶点的最短路径。
数组的长度为什么是2*(n*(m-1)+(n-1)m),是因为,隐含的“有向图“正好有这么多个顶点。考虑,从西向东的n条横着的路中的每一条,都被分成了m-1段,每段有一个中点(就是有向图的顶点),一共n(m-1)个中点,把道路从东向西看,还有n*(m-1)个中点(就是每个从西向东中点的马路对面)。
同理,从北向南的m条路,和从南到北的m条路,有2*(n-1)m个中点。
数组长度2
(n*(m-1)+(n-1)m)理解后,还要解决对应关系,即数组下标i(取值范围是0到2(n*(m-1)+(n-1)m)-1 )如何和一个中点(x1,y1,x2,y2)对应。
函数int map(int x1,int y1,int x2,int y2)用来解决这个对应的问题。函数map的参数就是中点(x1,y1,x2,y2),返回值就是这个中点在flag数组中的下标i(dist数组也一样)。实际上,flag数组的0— n
(m-1)-1这一段,依次存的是从西到东从北到南,每个横着路段南侧的中点;flag数组的 n*(m-1)----- 2n(m-1)-1这一段,依次存的是从西到东从北到南,每个横着路段北侧的中点;flag数组的
2n(m-1)--------2n(m-1)+(n-1)m-1这一段,依次存的是从西到东从北到南,每个竖着路段西侧的中点;flag数组的2n*(m-1)+(n-1)m------最后,这一段依次存的是从西到东从北到南,每个竖着路段东侧的中点。
函数void setxy(int * x1,int
y1,intx2,inty2,int cur)干的事情和map函数相反,即给出下标cur,计算x1,y1,x2,y2。
12,接着讲解迪杰斯特拉那个函数。
int cur=map(x1,y1,x2,y2),to;
变量cur是一个flag数组或者dist数组的下标,表示当前出发点(有向图顶点),to变量和cur一样也表示一个地点,用于记录cur的每个邻接点。
priority_queue q;
变量q是堆结构,类型Pos有两个成员index和value,index存有向图顶点编号(就是cur、to之类的那个下标),value存放与index表示顶点对应的路径长度(就是从出发点到当前点的路径)。q实际就是根据value值建立的小根堆。这个堆用于,每次取当前拥有最短的路径的那个顶点。
//q.push(Pos(cur,0));
double min_dist;//用于记录最短路径长度
flag[cur]=1;//printf(“%d map\n”,cur);//从起点出发
13,接下来。
while(1)
{}//很长的代码。如果你不熟悉迪杰斯特拉算法,请先看看数据结构书。
这么长的代码无非,就是试探当前点的每个未找到最短路径的邻接点,看看经过当期点,能否刷新曾经记录的最短路径长度。
14,还有一个double cal_time(int x1,int y1,int x2,int y2,double cur_t,int op)函数,用于返回,当前点到下一点需要的时间,参数int x1,int y1,int x2,int y2表示当前点,参数cur_t表示当前时间(用于计算红绿灯),op表示要进行的操作,0表示调头,1右转,2直行,3左转。

#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;

struct Pos
{
	int index;
	double value;
	Pos(int i,double v):index(i),value(v){
	}
	bool operator<(const Pos& r)const
	{
		return value>r.value;
	}
};
int n,m;
int h[105],w[105];
int g[105][105],r[105][105];
int map(int x1,int y1,int x2,int y2)
{
	if(x1==x2&&y1<y2)
	    return (x1-1)*(m-1)+y1-1;
	if(x1==x2&&y1>y2)
	    return (x1-1)*(m-1)+y2-1+n*(m-1);
	if(x1<x2&&y1==y2)
	    return (x1-1)*m+y1-1+2*n*(m-1);
	if(x1>x2&&y1==y2)
	    return (x2-1)*m+y1-1+2*n*(m-1)+(n-1)*m; 
}
double cal_time(int x1,int y1,int x2,int y2,
double cur_t,int op)
{
	if(op==0)//调头 
	{
		if(x1==x2) return w[y1<y2?y1:y2];
		else  return h[x1<x2?x1:x2];
	}
	if(op==1)//右转 
	{
		if(x1==x2&&y1<y2) //西向东转北向南 
		   return w[y1]*0.5+h[x1]*0.5;
		if(x1==x2&&y1>y2) //东向西转南向北 
		   return w[y2]*0.5+h[x1-1]*0.5;
		if(x1<x2&&y1==y2) //北向南转东向西 
		   return w[y1-1]*0.5+h[x1]*0.5;
		if(x1>x2&&y1==y2) //南向北转西向东 
		   return w[y1]*0.5+h[x2]*0.5;
	}
	if(op==2)//直行
	{
		double time;
		if(x1==x2)
		{
			if(y1<y2)
			{
				time=fmod(w[y1]*0.5+cur_t,g[x1][y2]+r[x1][y2]);
				if(time>=g[x1][y2])	time=0;
				else time=g[x1][y2]-time;			
				return w[y1]*0.5+w[y2]*0.5+time; 	
			}
			else
			{
				time=fmod(w[y2]*0.5+cur_t,g[x1][y2]+r[x1][y2]);
			    if(time>=g[x1][y2])	time=0;
			    else time=g[x1][y2]-time;
				return w[y2]*0.5+w[y2-1]*0.5+time; 	
			}	
		}
		else
		{
			if(x1<x2)
			{			
				time=fmod(h[x1]*0.5+cur_t,g[x2][y1]+r[x2][y1]);
				if(time<g[x2][y1])	time=0;
				else time=g[x2][y1]+r[x2][y1]-time;
				return h[x1]*0.5+h[x2]*0.5+time;
			}
			else
			{
				time=fmod(h[x2]*0.5+cur_t,g[x2][y1]+r[x2][y1]);
				if(time<g[x2][y1])	time=0;
				else time=g[x2][y1]+r[x2][y1]-time;
				return h[x2]*0.5+h[x2-1]*0.5+time;
			}		
		}		   
	}
	if(op==3)//左转 
	{
		double time;
		if(x1==x2&&y1<y2) //西向东转南向北
		{
			time=fmod(w[y1]*0.5+cur_t,g[x1][y2]+r[x1][y2]);
			if(time>=g[x1][y2])	time=0;
			else time=g[x1][y2]-time;
			return  w[y1]*0.5+h[x1-1]*0.5+time;
		} 		  
		if(x1==x2&&y1>y2) //东向西转北向南 
		{
			time=fmod(w[y2]*0.5+cur_t,g[x1][y2]+r[x1][y2]);
			if(time>=g[x1][y2])	time=0;
			else time=g[x1][y2]-time;
			return w[y2]*0.5+h[x1]*0.5+time;
		} 
		   
		if(x1<x2&&y1==y2) //北向南转西向东 
		{
		   	time=fmod(h[x1]*0.5+cur_t,g[x2][y1]+r[x2][y1]);
			if(time<g[x2][y1])	time=0;
			else time=g[x2][y1]+r[x2][y1]-time;			
			return w[y1]*0.5+h[x1]*0.5+time;
		} 
		   
		if(x1>x2&&y1==y2) //南向北转东向西 
		{
			time=fmod(h[x2]*0.5+cur_t,g[x2][y1]+r[x2][y1]);
			if(time<g[x2][y1])	time=0;
			else time=g[x2][y1]+r[x2][y1]-time;	
			return w[y1-1]*0.5+h[x2]*0.5+time;
		} 
		   
	} 
	
}
void setxy(int * x1,int*y1,int*x2,int*y2,int cur)
{
	if(cur<n*(m-1))
	{
		*x1=*x2=cur/(m-1)+1;
		*y1=cur%(m-1)+1;
		*y2=*y1+1;
	}
	else
	{
		cur-=n*(m-1);
		if(cur<n*(m-1))
		{
			*x1=*x2=cur/(m-1)+1;
			*y2=cur%(m-1)+1;
			*y1=*y2+1;
		}
		else 
		{
			cur-=n*(m-1);
			if(cur<(n-1)*m)
			{
				*x1=cur/m+1;
				*x2=*x1+1;
				*y1=*y2=cur%m+1;
			}
			else
			{
				cur-=(n-1)*m;
				*x2=cur/m+1;
				*x1=*x2+1;
				*y1=*y2=cur%m+1;
			}
			
		}
	}
}
double dj(int x1,int y1,int x2,int y2,
       int x3,int y3,int x4,int y4,
	   double t) 
{
	int flag[2*(n*(m-1)+(n-1)*m)];
	double dist[2*(n*(m-1)+(n-1)*m)];
	memset(flag,0,sizeof(int)*2*(n*(m-1)+(n-1)*m));
	memset(dist,0,sizeof(double)*2*(n*(m-1)+(n-1)*m));
	int cur=map(x1,y1,x2,y2),to;
	priority_queue<Pos> q;
	//q.push(Pos(cur,0));
	double min_dist;
	flag[cur]=1;//printf("%d map\n",cur);
	while(1)
	{
		double next_dist;
		//调头
		to=map(x2,y2,x1,y1);
		next_dist=cal_time(x1,y1,x2,y2,dist[cur]+t,0);
		if(!flag[to]&&(!dist[to]||dist[cur]+next_dist<dist[to])) 
		{  
			dist[to]=dist[cur]+next_dist;
			q.push(Pos(to,dist[to]));		
		}
		//右转
		to=-1;
		if(x1==x2&&y1<y2&&x1<n)
			to=map(x1,y2,x1+1,y2);
		if(x1==x2&&y1>y2&&x1>1)
		    to=map(x1,y2,x1-1,y2);
		if(x1<x2&&y1==y2&&y1>1)
		    to=map(x2,y1,x2,y1-1);
		if(x1>x2&&y1==y2&&y1<m)
		    to=map(x2,y1,x2,y1+1);
		if(to!=-1)
		{
			next_dist=cal_time(x1,y1,x2,y2,dist[cur]+t,1);
			if(!flag[to]&&(!dist[to]||dist[cur]+next_dist<dist[to])) 
			{
				dist[to]=dist[cur]+next_dist;
				q.push(Pos(to,dist[to]));
			}
		}
		//直行
		to=-1;
		if(x1==x2&&y1<y2&&y2<m)
			to=map(x1,y2,x1,y2+1);
		if(x1==x2&&y1>y2&&y2>1)
		    to=map(x1,y2,x1,y2-1);
		if(x1<x2&&y1==y2&&x2<n)
		    to=map(x2,y1,x2+1,y1);
		if(x1>x2&&y1==y2&&x2>1)
		    to=map(x2,y1,x2-1,y1);
		if(to!=-1)
		{
			next_dist=cal_time(x1,y1,x2,y2,dist[cur]+t,2);
			if(!flag[to]&&(!dist[to]||dist[cur]+next_dist<dist[to])) 
			{
				dist[to]=dist[cur]+next_dist;
			    q.push(Pos(to,dist[to]));
			} 
		}
		//左转
		to=-1;
		if(x1==x2&&y1<y2&&x1>1)
			to=map(x1,y2,x1-1,y2);
		if(x1==x2&&y1>y2&&x1<n)
		    to=map(x1,y2,x1+1,y2);
		if(x1<x2&&y1==y2&&y1<m)
		    to=map(x2,y1,x2,y1+1);
		if(x1>x2&&y1==y2&&y1>1)
		    to=map(x2,y1,x2,y1-1);
		if(to!=-1)
		{
			next_dist=cal_time(x1,y1,x2,y2,dist[cur]+t,3);
			if(!flag[to]&&(!dist[to]||dist[cur]+next_dist<dist[to])) 
			{
				dist[to]=dist[cur]+next_dist;
			    q.push(Pos(to,dist[to]));
			}
		}
		cur=q.top().index;
		min_dist=q.top().value;
		q.pop();
		setxy(&x1,&y1,&x2,&y2,cur);
//		printf("%f %d %d %d %d %d pos\n"
//		,min_dist, cur,x1,y1,x2,y2);
	 
		if(x1==x3&&y1==y3&&x2==x4&&y2==y4)
		{
		return min_dist;
		}
		  
		else flag[cur]=1;		 
	}
}
	
int main()
{
	int i,j;
	scanf("%d%d",&n,&m);	
	for(i=1;i<=n-1;i++)
	  scanf("%d",&h[i]);
	for(i=n-1;i>=2;i--)
	  h[i]-=h[i-1];
	
	for(i=1;i<=m-1;i++)
	  scanf("%d",&w[i]);
	for(i=m-1;i>=2;i--)
	  w[i]-=w[i-1];	
	for(i=1;i<=n;i++)
	  for(j=1;j<=m;j++)
	     scanf("%d",&g[i][j]);
	for(i=1;i<=n;i++)
	  for(j=1;j<=m;j++)
	     scanf("%d",&r[i][j]);
	int x1,y1,x2,y2,tx1,ty1,tx2,ty2;
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	tx1=x1,ty1=y1,tx2=x2,ty2=y2;
	int q;
	double re=0;
	scanf("%d",&q);
	int xi1,yi1,xi2,yi2,xi3,yi3,xi4,yi4;
	while(q--)
	{
		scanf("%d%d%d%d",&xi1,&yi1,&xi2,&yi2);
		re+=dj(x1,y1,x2,y2,xi1,yi1,xi2,yi2,re);
		//printf("%fre\n",re);
		scanf("%d%d%d%d",&xi3,&yi3,&xi4,&yi4);
		re+=dj(xi1,yi1,xi2,yi2,xi3,yi3,xi4,yi4,re);
		x1=xi3,y1=yi3,x2=xi4,y2=yi4;
	}
	re+=dj(xi3,yi3,xi4,yi4,tx1,ty1,tx2,ty2,re);
	printf("%.1f\n",re);
}
	
	
	
	

总结:难度不大,建模极端的麻烦。你考场没办法做啊(大佬除外)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐苏洋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值