日更计划Day3 CSP-J2019第四题

题目描述

有一个无向图,一号节点为0,无限更新相邻节点,每次更新为相邻节点编号加一。共有q次询问,分别询问对于i点是否更新过pi值。[题目传送门](http://hzjingma.com/?#/problem/6003)

错误思路分析

一开始看到这题时,我以为将所有节点用BFS更新一次,然后询问你找到所有相邻节点看看包含的最小奇数和偶数是否能够满足询问的数字。但是没有仔细看第二个例子,发现询问1,5时,我的程序并不会从1绕一圈跑回来因此得到5这个答案,所以这个办法行不通。

//错误思路代码
#include<bits/stdc++.h>
//#include "stdc++.h"
//#define int long long
using namespace std;
const int N = 1e5+5;
const int INF = 1e9;
int n,m,q,a,b,p,num;
int vis[N];
int ans[N];
struct node{
    int step;
};
vector<int>Map[N];
void BFS(int st){
    vis[st] = 1;
    ans[st] = 0;
    queue<int>q;
    q.push(st);
    while (q.size()) {
        int fr = q.front();
        q.pop();
        for (int i = 0; i < Map[fr].size(); i++){
            int v = Map[fr][i];     //说明fr与v之间有一条连线
            if (vis[v] != 0) continue;      //防止重复
            ans[v] = ans[fr]+1;
            vis[v] = 1;
            q.push(v);
        }
    }
}
string search(int p, int num){
    int MinE = INF;
    int MinO = INF;
    for (int i = 0; i < Map[p].size(); i++){
        int pos = Map[p][i];
        int app = ans[pos];
        if (app % 2 == 0){
            MinE = min(MinE,app);
        }else{
            MinO = min(MinO,app);
        }
    }
    cout << MinE << " " << MinO << endl;
    if(MinO == INF && num % 2 == 0){
        return "No\n";
    }
    if (MinE == INF && num % 2 != 0) return "No\n";
    if (num % 2 == 0){
        if (num >= MinO+1) return "Yes\n";
        if(MinO == INF) return "No\n";
    }else{
        if (num >= MinE+1) return "Yes\n";
        if (MinE == INF) return "No\n";
    }
    
    return "No\n";
}
int main(){
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++){
        cin >> a >> b;
        Map[a].push_back(b);
        Map[b].push_back(a);
    }
    BFS(1);
    for (int i = 1; i <= q; i++){
        cin >> p >> num;
        cout << search(p,num);
    }
    return 0;
}

正解思路

由于我们不知道从1到其他点是否能有奇数和偶数的解,但是和之前的错误思路相同,我们知道一个点只要能在5步到达就必然能够在7步到达(走出一步再走回来),然而最小到达步数是5的话,小于5的奇数步都不能够到达。于是,我们应该由1到所有点求一边奇数最短路以及偶数最短路。这里采用SPFA算法(参考落谷第一篇题解)。

#include<bits/stdc++.h>
//#include "stdc++.h"
//#define int long long
using namespace std;
const int N = 1e5+10;
int n,m,q,a,b,x,y,dist[N],odd[N],even[N];
vector<int>Map[N];
void SPFA(int u){
    queue<pair<int, int> >q;
    memset(odd, 0x3f, sizeof(odd));
    memset(even, 0x3f, sizeof(even));
    for (int i = 0; i < Map[1].size(); i++){
        odd[Map[1][i]] = 1;                 //连着1的最短奇数边都是1
        q.push(make_pair(Map[1][i], 1));
    }
    while (q.size()) {
        int p = q.front().first;
        int num = q.front().second;
        q.pop();
        for (int i = 0; i < Map[p].size(); i++){
            if (num % 2 == 0){
                //是偶数的话,更新奇数最短路(因为要走一步到当前枚举的点)
                if(num+1 < odd[Map[p][i]]){
                    odd[Map[p][i]] = num+1;
                    q.push(make_pair(Map[p][i], num+1));
                }
            }else{
                //是奇数的话,更新偶数最短路
                if(num+1 < even[Map[p][i]]){
                    even[Map[p][i]] = num+1;
                    q.push(make_pair(Map[p][i], num+1));
                }
            }
        }
    }
}
int main(){
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++) {
//        cin >> a >> b;
        scanf("%d %d", &a,&b);
        Map[a].push_back(b);
        Map[b].push_back(a);
    }
    SPFA(1);
    for (int i = 1; i <= q; i++){
//        cin >> x >> y;
        scanf("%d %d",&x,&y);
        if (y % 2 == 0){
            if (even[x] > y) printf("No\n");
            else printf("Yes\n");
        }else {
            if (odd[x] > y) printf("No\n");
            else printf("Yes\n");
        }
    }
    return 0;
}

总结

需要熟练运用最短路的几个模版,并且思考的更全面一些。

上一篇:Day3搭建JAVA开发环境


下一篇:day3 循环