CodeVs 3315 时空跳跃者的魔法(最终版本)

本文探讨了如何使用最小生成树算法解决四维空间中点与点之间的距离计算问题,通过Prim和Kruskal算法实现了无向图的最小生成树构建,并在实际应用中验证了算法的有效性。

实际上就是一颗最小生成树,所谓的四维空间可以算出每一个点之间的距离,而且是无向图,可以用Prim算法来实现。

Prim:

      1.O(n^2)

        
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
const long long  INF=0xffffff;
const int M=1005;
int n;
ll h;
ll hh;
struct zb
{
	ll x, y, z, t;
};
zb s[M];
ll cost[M];
int vis[M];
ll map[M][M];
void prim()
{
    for (ll i=1; i<=n; i++)
    {
    	ll ss;
    	ll minn=INF;
    	for (ll j=1; j<=n; j++)
    	{
    		if (!vis[j] && cost[j]<minn)
    		{
    			minn=cost[j];
    			ss=j;
    		}
    	}
    	vis[ss]=1;
    	hh+=minn;
    	for (ll j=1; j<=n; j++)
    	{
    		if (!vis[j] && map[ss][j]<cost[j] && map[ss][j]>0) cost[j]=map[ss][j];
    	}
    	
    }
}
void init()
{
	memset(map, 127, sizeof(map));
	memset(s, 0, sizeof(s));
	scanf("%d", &n);
	for (int i=1; i<=n; i++) scanf("%d %d %d %d", &s[i].x, &s[i].y,  &s[i].z,  &s[i].t);
	scanf( "%dTas", &h);
	for (int i=1; i<=n; i++)
	  for (int j=1; j<=n; j++)
	  {
	  	if (i!=j)
	  	{
	  	  map[i][j]=map[j][i]=floor(sqrt((s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y)+(s[i].z-s[j].z)*(s[i].z-s[j].z))+abs(s[i].t-s[j].t));
	    }
	  }
	for (ll i=1; i<=n; i++){
		cost[i]=INF;
		vis[i]=false;
	}
	cost[1]=0;
}
int main()
{
	init();
	prim();
	if (hh>h) printf("Death\n");
	else printf("%dTas", hh);
	return 0;
	
}




          2.O(n log2 n)

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<functional>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
FILE *fin = fopen ("magic.in","r");
FILE *fout = fopen("magic.out", "w");
typedef long long ll;
typedef pair <ll, int>P;
const long long  INF=0xffffff;
const int M=1005;
int n;
ll h;
ll hh;
struct zb
{
	ll x, y, z, t;
};
zb s[M];
ll cost[M];
int vis[M];
ll map[M][M];
void prim()
{
	priority_queue<P, vector<P>, greater<P> >que;
	que.push(P(0,1));
	while (!que.empty())
	{
		P s=que.top();
		que.pop();
		int v=s.second;
		if (cost[v]<s.first) continue;
		hh+=s.first;
		vis[v]=1;
		for (int i=1; i<=n; i++){
			if (!vis[i] && cost[i]>map[v][i] && map[v][i]>0){
				cost[i]=map[v][i];
				que.push(P(cost[i], i));
			}
		}
	}
}
void init()
{
	memset(map, 127, sizeof(map));
	memset(s, 0, sizeof(s));
	fscanf(fin, "%d", &n);
	for (int i=1; i<=n; i++) fscanf(fin, "%d %d %d %d", &s[i].x, &s[i].y,  &s[i].z,  &s[i].t);
	fscanf(fin, "%dTas", &h);
	for (int i=1; i<=n; i++)
	  for (int j=1; j<=n; j++)
	  {
	  	if (i!=j)
	  	{
	  	  map[i][j]=map[j][i]=floor(sqrt((s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y)+(s[i].z-s[j].z)*(s[i].z-s[j].z))+abs(s[i].t-s[j].t));
	    }
	  }
	for (ll i=1; i<=n; i++){
		cost[i]=INF;
		vis[i]=false;
	}
	cost[1]=0;
}
int main()
{
	init();
	prim();
	if (hh>h) fprintf(fout, "Death\n");
	else fprintf(fout, "%dTas", hh);
	return 0;
	
}



kruskal:

*需要注意的地方:kruskal我就不多讲了,讲一讲程序的地方。若点数为n,储存空间必须开到n*(n-1)/2约等于o(n^2),我一直卡在这里大半天了,感谢cmb老师给的提醒。
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=1000005; 
typedef long long ll;
const ll INF=0xffffff;
struct Edge
{
	int s;
	int t;
	ll val;
};
Edge s[M];  。 
ll x[M];
ll y[M];
ll z[M];
ll t[M];
ll n,h, hh;
int f[M];
ll side;     
int bfind(int x)
{
	if (f[x]==x) return x;
	f[x]=bfind(f[x]);
	return f[x];
}
void bunion(int x, int y)
{
	int x1=bfind(x);
	int y1=bfind(y);
	f[x1]=y1;
}
bool cmp(Edge a, Edge b)
{
	return a.val<b.val;
}
void kruskal()
{
	int i=1;
	int j=0;
	int v1, v2;
	sort(s+1, s+side+1, cmp);
	while (i<side)
	{
		v1=bfind(s[i].s);
		v2=bfind(s[i].t);
		if (v1!=v2)
		{
			bunion(v1, v2);
			hh+=s[i].val;
			if (++j==n-1) break;
		//	printf("%d", hh);
			
		}
		i++;
	}
}
void init()
{
	side=0;
	scanf ("%d", &n);
	for (int i=1; i<=n; i++) scanf("%d %d %d %d", &x[i], &y[i], &z[i], &t[i]);
	scanf("%dTas", &h);
	for (int i=1; i<=n; i++)
	  for (int j=1; j<=n; j++){
	  	if (i!=j)
	  	{
	  		s[++side].s=i;
	  		s[side].t=j;
	  		s[side].val=floor(sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j])))+abs(t[i]-t[j]);
	  	}
	  }
	  for (int i=1; i<=n; i++) f[i]=i;
}
int main()
{
	init();
	kruskal();
	if (hh<=h) printf("%dTas", hh);
	else printf("Death");
	return 0;
}


虽然没有直接关于时空漫游者的能量跳跃问题的变种介绍,但可根据华为机考真题示例推测可能存在的变种。 ### 不同地图类型 - **不规则地图**:原本的地图可能是规则的矩形,变种问题中地图可能变成不规则形状,例如带有障碍物的地图,在计算能量跳跃时需要避开这些障碍物。 - **三维地图**:从二维平面拓展到三维空间,时空漫游者不仅可以在平面上跳跃,还能在垂直方向上移动,能量消耗规则也会相应变化。 ### 跳跃规则变化 - **有限跳跃次数**:规定时空漫游者在整个过程中的最大跳跃次数,需要在有限次数内到达目标点,同时消耗最少能量。 - **跳跃方向限制**:例如只能朝特定的几个方向跳跃,而不是任意方向,这会影响到路径的选择和能量的计算。 ### 能量规则变化 - **能量动态变化**:地图上每个位置的能量消耗不是固定的,会随着时间或者漫游者的某些操作而动态变化。 - **能量积累与消耗并存**:漫游者在某些位置可以积累能量,而在其他位置消耗能量,需要合理规划路径来保证能量足够到达终点。 ### 多目标问题 - **多个目标点**:不再是单一的目标点,而是有多个目标点,需要在不同目标点之间选择最佳路径,同时考虑能量消耗。 - **多角色协作**:有多个时空漫游者同时进行跳跃,他们之间可能存在能量共享或者协作的关系,需要共同完成任务。 ```python # 示例代码:不规则地图跳跃(简单模拟) def irregular_jump(map, start, end): rows = len(map) cols = len(map[0]) directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] queue = [(start, 0)] visited = set() while queue: (x, y), energy = queue.pop(0) if (x, y) == end: return energy if (x, y) in visited: continue visited.add((x, y)) for dx, dy in directions: new_x, new_y = x + dx, y + dy if 0 <= new_x < rows and 0 <= new_y < cols and map[new_x][new_y] != -1: # -1 表示障碍物 new_energy = energy + map[new_x][new_y] queue.append(((new_x, new_y), new_energy)) return -1 # 示例地图 map = [ [1, 2, -1, 3], [4, 5, 6, 7], [-1, 8, 9, 10] ] start = (0, 0) end = (2, 3) print(irregular_jump(map, start, end)) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值