2月21日 天梯赛刷题记录(L2开始)

L2-001 紧急救援 (25 分)

在这里插入图片描述
在这里插入图片描述

分析:

  一看就是迪杰斯特拉 求最短路径,但是还是有点晕,今晚就去看看,之前做作业的时候就是抄的网上的。除了求最短路径外,还要记录路径的条数,救援队的数量,当然 路径距离一样的情况下 肯定是优先走救援队最多的。每次找到最短路的时候 记录前驱,递归函数打印路径。

代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,m,c1,c2;//N城市个数,M快速路条数,c1出发地编号,c2目的地编号
int weight[510],dis[510],e[510][510],num[510],w[510],pre[510];
int visit[510];
const int inf =9999999;
void printPath(int v)//利用递归 打印路径(路径本身顺序是倒着的) 
{
	if(v==c1)
	{
		printf("%d",v);//递归退出条件 
		return ;
	}
	printPath(pre[v]);
	printf(" %d",v); 
 } 
int main()
{ 
	scanf("%d%d%d%d",&n,&m,&c1,&c2);
	for(int i=0;i<n;i++)
		scanf("%d",&weight[i]);//每个城市的救援队数量
	fill(e[0],e[0]+510*510,inf);
	fill(dis,dis+510,inf);//初始化每个城市的最短距离 与每个城市之间的快速路长度
	int a,b,c;
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		e[a][b]=c;
		e[b][a]=c;//根据输入完成城市地图的构造 
	 } 
	dis[c1]=0;//从起点到起点的距离为0
	w[c1]=weight[c1];//到起点 能叫的救援队最多为起点本地的救援队数量
	num[c1]=1;//道路有1条
	for(int i=0;i<n;i++)//用迪杰斯特拉找到 到每个点最短距离 
	{
		int u=-1,minn=inf;
		for(int j=0;j<n;j++)//找到当前可以到达的距离最短的点 
		{
			if(visit[j]==false&&dis[j]<minn)
			{
				u=j;
				minn=dis[j];//目前的最短距离 
			 }  
		} 
		if(u==-1) break;//说明所有的点都已经找到
		visit[u]=true;
		for(int v=0;v<n;v++)
		{
			if(visit[v]==false&&e[u][v]!=inf)//从剩下没到达的点找 
			{
				if(dis[u]+e[u][v]<dis[v])//如果到v点 通过u 更短 刷新v的dis 
				{
					dis[v]=dis[u]+e[u][v];
					num[v]=num[u];//路的条数是一样的 
					w[v]=w[u]+weight[v];//救援队数量增多
					pre[v]=u;//v的前驱是u 
				 } 
				else if(dis[u]+e[u][v]==dis[v])//如果距离一样 说明多了一条路 
				{
					num[v]=num[v]+num[u];
					if(w[u]+weight[v]>w[v])//距离一样的情况下 肯定优先走救援队伍多的路 
					{
						w[v]=w[u]+weight[v];
						pre[v]=u;
					 } 
				}
			}
		} 
	 } 
	 printf("%d %d\n",num[c2],w[c2]);
	 printPath(c2);
	 return  0;
} 
L2-002 链表去重 (25 分)

在这里插入图片描述
在这里插入图片描述

代码:

  晕死了 看了半天也不知道为啥测试点4和5过不了

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
typedef struct 
{
	int key;
	int next;
}Node;
void bu(int i)
{
	if(i==-1)
		return;
	if(i>=0&&i<10)//只有个位
		cout<<"0000";
	else if(i<100)//只要十位
		cout<<"000" ;
	else if(i<1000)//只有百位
		cout<<"00";
	else if(i<10000)
		cout<<"0"; 
 } 
int main()
{ 
	Node res[100000];
	int first,num;
	scanf("%d %d",&first,&num);//输入第一个结点地址 与结点总数
	for(int i=0;i<num;i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);//输入结点
		res[a].key=b;
		res[a].next=c; 
	}
	int p=first;//第一个开始 
	bool isdel=false;//标记是否已经有删除链表 
	bool d[10001];//是否重复
	fill(d,d+10001,false);
	d[res[p].key]=true;//初始化第一个 
	int dfirst=-1;
	int q=-1;
	while(res[p].next!=-1)
	{
		if(d[abs(res[res[p].next].key)]==false)//如果绝对值没有重复
		{
			d[abs(res[res[p].next].key)]=true;
			p=res[p].next;
		} 
		else//如果重复 
		{
			if(isdel==false)//如果在此之前还没有重复的
			{
				dfirst=res[p].next;//让其变成删除链表的第一个
				q=dfirst;
				res[p].next=res[res[p].next].next;//等于下下个 
				isdel=true; 
			}
			else//删除重复结点 
			{
				res[q].next=res[p].next;//接在删除链表后面 
				res[p].next=res[res[p].next].next;//让其下一个变成其下一个的下一个
				q=res[q].next;
			} 
		} 
	}//该循环还没有处理最后一个结点
	res[q].next=-1;
	p=first;
	q=dfirst;
	while(p!=-1)
	{
		bu(p);
		cout<<p<<' '<<res[p].key<<' ';
		bu(res[p].next);
		cout<<res[p].next<<endl;
		p=res[p].next;
	}
	while(q!=-1)
	{
		bu(q);
		cout<<q<<' '<<res[q].key<<' ';
		bu(res[q].next);
		cout<<res[q].next<<endl;
		q=res[q].next;
	}
	
} 
分析:

  自己的死活过不了,只好去看大佬的了。大佬的想法有点神奇,大概是把整个链表放在同一个数组内保存,分成两部分,一部分是没重复的,一部分是重复的。通过给编号(给编号的时候是按照链表的顺序给的)将两个部分分隔开 排序后 ,不是用Next输出下一个,而是数组的下一个(就是正常情况的next 先输入的输出)

代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=100000;
struct NODE{
	int address;
	int key;
	int next;
	int num;
}node[maxn];
bool exist[maxn];
int cmp1(NODE a,NODE b)
{
	return a.num<b.num;//根据编号排序 
}
int main()
{ 
	int begin,n,cnt1=0,cnt2=0,a;//cnt1没有删除的结点个数
	scanf("%d%d",&begin,&n);
	for(int i=0;i<maxn;i++)
	{
		node[i].num=2*maxn;//初始化编号 
	} 
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a);//地址 
		scanf("%d%d",&node[a].key,&node[a].next);//值与下一个的地址 
		node [a].address =a; 
	}
	for(int i=begin;i!=-1;i=node[i].next)
	{
		if(exist[abs(node[i].key)]==false)//如果没有重复 
		{
			exist[abs(node[i].key)]=true;
			node[i].num=cnt1;
			cnt1++;
		}
		else
		{
			node[i].num=maxn+cnt2;
			cnt2++;
		}
	}
	sort(node,node+maxn,cmp1);//按照编号排序
	int cnt=cnt1+cnt2;//总共需要输出的数量
	for(int i=0;i<cnt;i++)
	{
		if(i!=cnt1-1&&i!=cnt-1)
		{
			printf("%05d %d %05d\n",node[i].address,node[i].key,node[i+1].address);
		}
		else
		{
			printf("%05d %d -1\n",node[i].address,node[i].key);
			
		}
	 } 
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值