题解 P5663 【加工零件【民间数据】】

博客园体验更佳

凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇。工厂里有 nn 位工人,工人们从 1n1 sim n 编号。某些工人之间存在双向的零件传送带。保证每两名工人之间最多只存在一条传送带。

如果 xx 号工人想生产一个被加工到第 L(L>1)L (L gt 1) 阶段的零件,则所有xx 号工人有传送带直接相连的工人,都需要生产一个被加工到第 L1L - 1 阶段的零件(但 xx 号工人自己无需生产第 L1L - 1 阶段的零件)。

如果 xx 号工人想生产一个被加工到第 11 阶段的零件,则所有与 xx 号工人有传送带直接相连的工人,都需要为 xx 号工人提供一个原材料。

轩轩是 11 号工人。现在给出 qq 张工单,第 ii 张工单表示编号为 aia_i 的工人想生产一个第 LiL_i 阶段的零件。轩轩想知道对于每张工单,他是否需要给别人提供原材料。他知道聪明的你一定可以帮他计算出来!

讲讲我的做法

确定做法

首先,看到这道题,我直接想到的是递归,于是复杂度就上天了,考虑最短路

如何用最短路

首先,看一张图

360截图16251114373524.png

我们该如何解决问题?

问题:3355阶段的零件11要不要做呢?

其实,实质就是看3311有没有长度为55的路径。

问题:3377阶段的零件11要不要做呢?

其实,实质就是看3311有没有长度为77的路径。

问题:3366阶段的零件11要不要做呢?

其实,实质就是看3311有没有长度为66的路径。

仔细思考这33个问题,我们会发现,如果3311有长度为55的路径,那么3311一定有长度为77的路径,但并不一定有长度为66的路径。

所以,我们要对每个点求一遍奇数路径,和偶数路径。

实现最短路

最短路的算法有很多,这道题最好用dijkstradijkstra,或bfsbfs

这道题的时限并不紧,并且dijkstradijkstra细节太多,我就来演示bfsbfs实现的最短路

void bfw(){//我有一个好朋友叫bfw,所以我写bfs时,喜欢把函数名起为bfw
	memset(ji,0x3f,sizeof(ji));//奇数最短路径
	memset(ou,0x3f,sizeof(ou));//偶数最短路径
	queue<pair<int,int> >q;
	q.push(make_pair(1,0));
    ou[1]=0;
	while(q.size()){
		int x=q.front().first,y=q.front().second;
		for(int i=0;i<v[x].size();i++){
			if(y%2==1){//奇数+1=偶数
				if(y+1<ou[v[x][i]]){
					ou[v[x][i]]=y+1;//更新答案
					q.push(make_pair(v[x][i],y+1));
				}
			}else{//偶数+1=奇数
				if(y+1<ji[v[x][i]]){
					ji[v[x][i]]=y+1;//更新答案
					q.push(make_pair(v[x][i],y+1));
				}
			}
		}
		q.pop();
	}
}

vv数组是一个动态数组,也就是vectorvector,曹老师教我们多用STLSTL写程序

如果你写这样的bfsbfs民间数据会WAWA 11个点 ,这个点是这样的

360截图172905077510285.png

11号点是一个孤点,没有偶数路径,所以,我们的bfsbfs要这么写

void bfw(){//我有一个好朋友叫bfw,所以我写bfs时,喜欢把函数名起为bfw
	memset(ji,0x3f,sizeof(ji));//奇数最短路径
	memset(ou,0x3f,sizeof(ou));//偶数最短路径
	queue<pair<int,int> >q;
	for(int i=0;i<v[1].size();i++){
		ji[v[1][i]]=1;
		q.push(make_pair(v[1][i],1));
	}
	while(q.size()){
		int x=q.front().first,y=q.front().second;
		for(int i=0;i<v[x].size();i++){
			if(y%2==1){//奇数+1=偶数
				if(y+1<ou[v[x][i]]){
					ou[v[x][i]]=y+1;//更新答案
					q.push(make_pair(v[x][i],y+1));
				}
			}else{//偶数+1=奇数
				if(y+1<ji[v[x][i]]){
					ji[v[x][i]]=y+1;//更新答案
					q.push(make_pair(v[x][i],y+1));
				}
			}
		}
		q.pop();
	}
}

简要讲解主程序

有了这些主程序应该是很简单的了

int main(){
	int n,m,q;
	read(n);read(m);read(q);
	for(int i=1;i<=m;i++){
		int x,y;
		read(x);read(y);//无向边
		v[x].push_back(y);//连边
		v[y].push_back(x);//连边
	}
	bfw();//跑最短路
	while(q--){
		int x,y;
		read(x);read(y);
		if(y%2==0){
			if(ou[x]>y)puts("No");//如果大于就不可能了
			else puts("Yes");
		}else{
			if(ji[x]>y)puts("No");//如果大于就不可能了
			else puts("Yes");
		}
	}
	return 0;
}

总结

先来看一看这题完整的代码了

#include <bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &FF){
	T RR=1;FF=0;char CH=getchar();
	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
	FF*=RR;
}
template<typename T>void write(T x){
	if(x<0)putchar('-'),x*=-1;
	if(x>9)write(x/10);
	putchar(x%10+48);
}
vector<int>v[100010];
int ji[100010],ou[100010];
void bfw(){//我有一个好朋友叫bfw,所以我写bfs时,喜欢把函数名起为bfw
	memset(ji,0x3f,sizeof(ji));//奇数最短路径
	memset(ou,0x3f,sizeof(ou));//偶数最短路径
	queue<pair<int,int> >q;
	for(int i=0;i<v[1].size();i++){
		ji[v[1][i]]=1;
		q.push(make_pair(v[1][i],1));
	}
	while(q.size()){
		int x=q.front().first,y=q.front().second;
		for(int i=0;i<v[x].size();i++){
			if(y%2==1){//奇数+1=偶数
				if(y+1<ou[v[x][i]]){
					ou[v[x][i]]=y+1;//更新答案
					q.push(make_pair(v[x][i],y+1));
				}
			}else{//偶数+1=奇数
				if(y+1<ji[v[x][i]]){
					ji[v[x][i]]=y+1;//更新答案
					q.push(make_pair(v[x][i],y+1));
				}
			}
		}
		q.pop();
	}
}
int main(){
	int n,m,q;
	read(n);read(m);read(q);
	for(int i=1;i<=m;i++){
		int x,y;
		read(x);read(y);//无向边
		v[x].push_back(y);//连边
		v[y].push_back(x);//连边
	}
	bfw();//跑最短路
	while(q--){
		int x,y;
		read(x);read(y);
		if(y%2==0){
			if(ou[x]>y)puts("No");//如果大于就不可能了
			else puts("Yes");
		}else{
			if(ji[x]>y)puts("No");//如果大于就不可能了
			else puts("Yes");
		}
	}
	return 0;
}

这道题还是比较有思维含量的,民间数据也出的很好,让我们思考全面。

最后,还是希望大家不懂就在评论区问,觉得好就点赞!

原文地址:https://www.cnblogs.com/zhaohaikun/p/12817008.html