2019 CCF CSP-J2 第4题:加工零件 ← 链式前向星

82 篇文章 3 订阅
73 篇文章 1 订阅
该博客详细介绍了如何使用链式前向星存储图,并通过广度优先搜索(BFS)求解节点间的最短路径。文章讨论了路径长度的奇偶性及其与最短路径的关系,并给出了一段C++代码实现。在处理工作订单需求时,判断从源节点到目标节点是否存在满足长度条件的路径。
摘要由CSDN通过智能技术生成

【问题描述】
https://www.luogu.com.cn/problem/P5663

【算法分析】
若结点u到结点v间存在长度为L的路径,那么也一定存在长度为L+2、L+4、L+6、……的路径。因为这可以通过重复经过路径中的某些结点来实现。而且,这些路径长度的奇偶性相同,即若L为奇数,则L+2、L+4、L+6等也为奇数,若L为偶数,则L+2、L+4、L+6等也为偶数。
若结点u到结点v间
存在长度为L的路径,且L大于等于结点u到结点v间的最短路径dis,即L>=dis,那么当结点v生产第L阶段的零件时,需要结点u提供原材料
特殊情况需要特判,即当结点u与其他结点均不连通时,直接输出"No"即可。

● 大佬 yxc 指出“链式前向星”就是“多单链表”,并基于“头插法”给出了所涉及到的 e[]、ne[]、h[] 等数组的独特解释,更易理解。其中:
h[a]:存储单链表表头结点 a 的编号
e[idx]:存储结点 idx 的值
ne[idx]:存储结点 idx 的下一个结点的编
参见:https://blog.csdn.net/hnjzsyjyj/article/details/139369904

【算法代码】

/* 链式前向星存图
val[idx] 表示第 idx 条边的权值。
h[a]:存储单链表表头结点 a 的编号
e[idx]:存储结点 idx 的值
ne[idx]:存储结点 idx 的下一个结点的编号
*/

#include <bits/stdc++.h>
using namespace std;

const int N=100010;
const int M=N<<1;

int h[N],e[M],ne[M],idx;
int dis[N][2]; //dis[u][0]/dis[u][1]:Shortest path to u with even/odd length
int q[M]; //Number of work orders

void add(int a,int b) {
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void bfs() {
	memset(dis,0x3f3f3f3f,sizeof(dis));

	dis[1][0]=0; //The shortest path length is 0 when it reaches itself through zero edges

	int hh=0, tt=0;
	q[tt]=1; //enqueue node 1

	while(hh<=tt) {
		int u=q[hh++];

		for(int i=h[u]; i!=-1; i=ne[i]) {
			int v=e[i];

			//Extend from u through an odd number of edges to v,
			//update dis[v][0] if relaxation can be done.
			if(dis[v][0]>dis[u][1]+1) {
				dis[v][0]=dis[u][1]+1;
				q[++tt]=v;
			}

			//Extend from u through an even number of edges to v,
			//update dis[v][1] if relaxation can be done.
			if(dis[v][1]>dis[u][0]+1) {
				dis[v][1]=dis[u][0]+1;
				q[++tt]=v;
			}
		}
	}
}

int main() {
	int n,m,q; //number of workers, number of conveyor belts, number of work orders
	cin>>n>>m>>q;

	memset(h,-1,sizeof(h));
	for(int i=0; i<m; i++) {
		int u,v;
		cin>>u>>v;
		add(u,v), add(v,u); //undirected graph
	}

	bfs();

	while(q--) {
		int u,L;
		cin>>u>>L;
		if(h[1]==-1) cout<<"No"<<endl; //Node 1 is disconnected with other points
		else if(dis[u][L&1]<=L) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}

	return 0;
}


/*
in1:
3 2 6
1 2
2 3
1 1
2 1
3 1
1 2
2 2
3 2

out1:
No
Yes
No
Yes
No
Yes
---------
in2:
5 5 5
1 2
2 3
3 4
4 5
1 5
1 1
1 2
1 3
1 4
1 5

out2:
No
Yes
No
Yes
Yes
*/



【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/139369904
https://blog.csdn.net/qiaoxinwei/article/details/108982789

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值