[CSP-S 2022] 假期计划

目录

1. 题目大意:

2. 解题思路:链表

1)预处理

2)寻找符合条件的路径:

3)优化

3. 完整代码

最后附上vector 用法:


1. 题目大意:

https://www.luogu.com.cn/problem/P8817

2. 解题思路:链表

首先预处理,存每个点从此处到达另外图中所有的点需要转车的次数

然后寻找符合小于k次的,且分值最大的一条路径

1)预处理

void bfs(int start)
{
	queue<int> q;
	int dist[N];
	memset(dist,0x3f,sizeof(dist));
	dist[start]=0;
	q.push(start);
	while(q.size())
	{
		int t=q.front();
		q.pop();
		if(dist[t]==k+1) continue;
		for(int i=h[t];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dist[j]>dist[t]+1)
			{
				st[start][j]=1;//标记是否能够从start节点到j节点
				dist[j]=dist[t]+1;
				q.push(j);
			}
		}		
	}
}

本段代码注释:

从start点开始,到每一个点的换车次数初始值为最大值,到自己的换车次数设置为零,然后进队。

如果队不为空,则判断start到 t (队头点)的换车次数是否符合规定,不符合则直接跳过节省时间。

遍历链表,如果从start点到相邻的e[i]点换成次数大于从 t 结点+1(即加了一次换车),则替换dist值并且入队,标记。

2)寻找符合条件的路径:

    for(int a=2;a<=n;a++)
	{
		if(st[1][a])
		{
			for(int b=2;b<=n;b++)
			{
				if(st[a][b])
				for(int c=2;c<=n;c++)
				{
					if(st[b][c] && a!=c)
					{
						for(int d=2;d<=n;d++)
						{
							if(st[c][d] && st[d][1] && a!=d && b!=d)
							{
								ans=max(ans,w[a]+w[b]+w[c]+w[d]);							
							}
						}					
					}
				}
			}
		}
		
	}

三个要点:是否连通(我们在预处理时已经将大于转车次数的叉出去了),是否不等(两个点之间不等),是否为最大值

最后输出ans

但是,超时了

3)优化

优化数组和时间

数组:我们发现用二维数组时,如果输入数据规模小,那么剩下的位置就会被浪费,所以我们采用动态数组vector

时间:

void bfs(int x)
{
	queue<node> q;
	q.push({x,0});
	while(q.size())
	{
		node h=q.front();
		q.pop();
		if(h.step==k+1) continue;
		for(auto i:g[h.num ])//vector遍历
		{
			if(st[x][i]>h.step+1 && i!=x)
			{
				st[x][i]=h.step+1;
				q.push({i,h.step+1});
				if(st[1][i]<=k+1)
				{
					f[x][4]=i;
					sort(f[x]+1,f[x]+5,cmp);
				}
			}
		}
	}
}

在符合从家到第i个点转车次数小于k的情况下,将从x到第4个景区的经过的点存为i,再将f[]排序,取最大值。

这里我们主要用的是枚举四个景区a b c d 中 b c 两个景点

3. 完整代码

75分未优化版代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2505,M=10005;
long long w[N];
int n,m,k;
int h[N],e[M*2],ne[M*2],idx;
int st[N][N];
long long ans=0;
void bfs(int start)
{
	queue<int> q;
	int dist[N];
	memset(dist,0x3f,sizeof(dist));
	dist[start]=0;
	q.push(start);
	while(q.size())
	{
		int t=q.front();
		q.pop();
		if(dist[t]==k+1) continue;
		for(int i=h[t];i!=-1;i=ne[i])
		{
			int j=e[i];
			if(dist[j]>dist[t]+1)
			{
				st[start][j]=1;
				dist[j]=dist[t]+1;
				q.push(j);
			}
		}		
	}
}
void add(int x,int y)//建边
{
	e[++idx]=y;
	ne[idx]=h[x];
	h[x]=idx;
}
int main()
{
	memset(h,-1,sizeof(h));
	int x,y;
	cin>>n>>m>>k;
	for(int i=2;i<=n;i++) cin>>w[i];
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		add(x,y);
		add(y,x);//建图 
	}
	//预处理 任何景点之间能否k次 中转到达 
	for(int i=1;i<=n;i++)
	{
		bfs(i);
	}
	//枚举a b c d是否满足题干要求 
	for(int a=2;a<=n;a++)
	{
		if(st[1][a])
		{
			for(int b=2;b<=n;b++)
			{
				if(st[a][b])
				for(int c=2;c<=n;c++)
				{
					if(st[b][c] && a!=c)
					{
						for(int d=2;d<=n;d++)
						{
							if(st[c][d] && st[d][1] && a!=d && b!=d)
							{
								ans=max(ans,w[a]+w[b]+w[c]+w[d]);							
							}
						}					
					}
				}
			}
		}
		
	}
	cout<<ans;
	return 0;
} 

满分:

#include<bits/stdc++.h>
using namespace std;
const int N=2505,M=10005;
int n,m,k;
long long w[N],ans;
int st[N][N],f[N][5];
vector<int> g[N];
struct node
{
	int num,step;
};
int cmp(int a,int b)
{
	return w[a]>w[b];
}
void bfs(int x)
{
	queue<node> q;
	q.push({x,0});
	while(q.size())
	{
		node h=q.front();
		q.pop();
		if(h.step==k+1) continue;
		for(auto i:g[h.num ])
		{
			if(st[x][i]>h.step+1 && i!=x)
			{
				st[x][i]=h.step+1;
				q.push({i,h.step+1});
				if(st[1][i]<=k+1)
				{
					f[x][4]=i;
					sort(f[x]+1,f[x]+5,cmp);
				}
			}
		}
	}
}
int main()
{
	int x,y;
	cin>>n>>m>>k;
	for(int i=2;i<=n;i++) cin>>w[i];
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x);//双向建边  
	}
	memset(st,0x3f,sizeof(st));
	for(int i=1;i<=n;i++)
	{
		bfs(i);
	}
	//枚举a b c d是否满足题干要求 
	ans=0;
	int a,b,c,d;
	for(b=2;b<=n;b++)
	{
		for(c=2;c<=n;c++)
		{
			if(st[b][c]<=k+1)
			{
				for(int i=1;i<=3;i++)
				{
					for(int j=1;j<=3;j++)
					{
						a=f[b][i];
						d=f[c][j];
						if(a && d && a!=d && a!=c && b!=d)
						{
							ans=max(ans,w[a]+w[b]+w[c]+w[d]);
						}
					}
				}
			}
		}
	}
	cout<<ans;
	return 0;
} 

最后附上vector 用法:

《夹带私货》 语法 vector用法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值