洛谷 P5663 加工零件 & [NOIP2019普及组] (奇偶最短路)

传送门


解题思路

很容易想到用最短路来解决这一道问题(题解法),因为两个点之间可以互相无限走,所以如果到某个点的最短路是x,那么x+2,x+4也一定能够达到。

但是如何保证这是正确的呢?比如说到某个点的最短路是x,为什么不可能走一下弯路,是某一条路径的长度是x+1或者x+3或者x+5呢?

所以就用到了奇偶最短路所谓奇偶最短路,就是对于每一个点,记录下走偶数步的最短路(ou[i])和走奇数步的最短路(ji[i]),转移式为:

ji[v]=min(ou[u]+1,ji[v]);

ou[v]=min(ji[u]+1,ou[v]);

注意一定要用u去更新v,即距离近的去更新远的。

AC代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn=100005;
 7 int n,m,Q;
 8 int ji[maxn],ou[maxn],vis[maxn],p[maxn];
 9 queue<int> q;
10 struct edge{
11     int v,next;
12 }e[2*maxn];
13 int cnt;
14 void insert(int u,int v){
15     e[++cnt].v=v;
16     e[cnt].next=p[u];
17     p[u]=cnt;
18 }
19 int main(){
20     memset(ji,0x3f,sizeof(ji));
21     memset(ou,0x3f,sizeof(ou));
22     memset(p,-1,sizeof(p));
23     cin>>n>>m>>Q;
24     for(int i=1;i<=m;i++){
25         int u,v;
26         scanf("%d%d",&u,&v);
27         insert(u,v);
28         insert(v,u);
29     }
30     ou[1]=0;
31     q.push(1);
32     while(!q.empty()){
33         int u=q.front();
34         q.pop();
35         vis[u]=0;
36         for(int i=p[u];i!=-1;i=e[i].next){
37             int v=e[i].v;
38             if(ji[v]>ou[u]+1){
39                 ji[v]=ou[u]+1;
40                 if(vis[v]==0){
41                     q.push(v);
42                     vis[v]=1;
43                 } 
44             }
45             if(ou[v]>ji[u]+1){
46                 ou[v]=ji[u]+1;
47                 if(vis[v]==0){
48                     q.push(v);
49                     vis[v]=1;
50                 }
51             }
52         }
53     }
54     for(int i=1;i<=Q;i++){
55         int a,l;
56         scanf("%d%d",&a,&l);
57         if(((l&1)&&ji[a]<=l)||((!(l&1))&&ou[a]<=l))printf("Yes\n");
58         else printf("No\n");
59     }
60     return 0;
61 } 

//CSP2019普及组 t4

posted @ 2019-12-06 21:10  尹昱钦  阅读(862)  评论(0编辑  收藏  举报