Luogu P5663 [CSP-J 2019] 零件加工(图论-SPFA)

来源:Luogu P2966,JZOJ #318

题目描述

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

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

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

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

解题思路

  • 我们想象 1 1 号点到 i i 号点有一条长度为 L L 的路径
  • 因为L>0 ,而且可以在路径中选一条边来回走
  • 所以就可以构造 L+2 L+4 L+6 ……
  • 因此只要有一条长度是L的路径,那么就能构造出所有长度大于等于L,而且奇偶性相同的路径。
  • 假设L为奇数或偶数
  • 如果要求出 一条长度为L的路径,也就是说必须有一条长度为奇数的路径。
  • (如果要求出 一条长度为L的路径,也就是说必须有一条长度为偶数的路径。)
    我们就求出从1到i 的长度为奇数的最短路 d i s o [ i ] dis_o[i] ,
    题目求是否存在一条长度为L的路径其实等于 L > = d i s e [ i ] ( o d d ) L>= dis_e[i] (odd)
  • L是偶数 L > = d i s e [ i ] ( e v e n ) L>=dis_e[i] (even)
  • i i j j 有一条边 d i s o [ y ] = m i n ( d i s o [ y ] , d i s e [ x ] + 1 ) ; dis_o[y]=min(dis_o[y],dis_e[x]+1);
    d i s e [ y ] = m i n ( d i s e [ y ] , d i s o [ x ] + 1 ) ; dis_e[y]=min(dis_e[y],dis_o[x]+1);

代码君

#include <bits/stdc++.h>
using namespace std;
const int MAXN=100000*2+10;
int t=0,n,m,q;
int dis_e[MAXN],dis_o[MAXN],linkk[MAXN],Q[MAXN],vis[MAXN];
struct node
{
	int y,next;
}e[MAXN];
void insert(int x,int y)
{
	e[++t].y=y;
	e[t].next=linkk[x]; linkk[x]=t;
}
void SPFA(int st)  //SPFA
{
	memset(dis_e,10,sizeof(dis_e));
	memset(dis_o,10,sizeof(dis_o));
	memset(vis,0,sizeof(vis));
	dis_e[st]=0; vis[st]=1;
	int head=1,tail=1;
	Q[head]=st;
	for (head=1;head<=tail;head++)
	{
		int x=Q[head];  //取出队头
		for (int i=linkk[x];i>0;i=e[i].next)  //邻接表查询
		{
			int y=e[i].y;
			if (dis_e[x]+1<dis_o[y] || dis_o[x]+1<dis_e[y])
			{
				dis_o[y]=min(dis_o[y],dis_e[x]+1);  //更新最优解
				dis_e[y]=min(dis_e[y],dis_o[x]+1);
				Q[++tail]=y;  //入队
				vis[y]=1;
			}
		}
		vis[x]=0;  //出队
	}
}
int main()
{
	freopen("work.in","r",stdin);
	freopen("work.out","w",stdout);
	scanf("%d %d %d",&n,&m,&q);
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		insert(x,y);  //邻接表存储
		insert(y,x);
	}
	SPFA(1);
	for (int i=1;i<=q;i++)  //q次询问
	{
		int a,L;
		scanf("%d %d",&a,&L);
		if (L%2==1 && L>=dis_o[a] || L%2==0 && L>=dis_e[a])  //判断是否可行
		{
			printf("Yes\n");
		}
		else
		{
			printf("No\n");
		}
	}
	return 0;
}
发布了27 篇原创文章 · 获赞 33 · 访问量 1688

猜你喜欢

转载自blog.csdn.net/qq_43081996/article/details/104165913
今日推荐