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

讲讲我的做法

确定做法

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

如何用最短路

首先,看一张图

我们该如何解决问题?

问题:\(3\)做\(5\)阶段的零件\(1\)要不要做呢?

其实,实质就是看\(3\)到\(1\)有没有长度为\(5\)的路径。

问题:\(3\)做\(7\)阶段的零件\(1\)要不要做呢?

其实,实质就是看\(3\)到\(1\)有没有长度为\(7\)的路径。

问题:\(3\)做\(6\)阶段的零件\(1\)要不要做呢?

其实,实质就是看\(3\)到\(1\)有没有长度为\(7\)的路径。

仔细思考这\(3\)个问题,我们会发现,如果\(3\)到\(1\)有长度为\(5\)的路径,那么\(3\)到\(1\)一定有长度为\(7\)的路径,但并不一定有长度为\(6\)的路径。

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

实现最短路

最短路的算法有很多,这道题最好用\(dijkstra\),或\(bfs\)。

这道题的时限并不紧,并且\(dijkstra\)细节太多,我就来演示\(bfs\)实现的最短路

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();
    }
}

\(v\)数组是一个动态数组,也就是\(vector\),曹老师教我们多用\(STL\)写程序

如果你写这样的\(bfs\)民间数据会\(WA\) \(1\)个点 ,这个点是这样的

\(1\)号点是一个孤点,没有偶数路径,所以,我们的\(bfs\)要这么写

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/12180821.html

时间: 2024-10-17 19:54:49

题解 P5663 【加工零件【民间数据】】的相关文章

洛谷 P3955 图书管理员【民间数据】

P3955 图书管理员[民间数据] 题目背景 数据已再次修正 (既然你们不要前导0我就去掉了) 题目描述 图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个 正整数. 每位借书的读者手中有一个需求码,这个需求码也是一个正整数.如果一本书的图 书编码恰好以读者的需求码结尾,那么这本书就是这位读者所需要的. 小 D 刚刚当上图书馆的管理员,她知道图书馆里所有书的图书编码,她请你帮她写 一个程序,对于每一位读者,求出他所需要的书中图书编码最小的那本书,如果没有他 需要的书,请输出

洛谷P3954 成绩【民间数据】

题目背景 数据已修复 题目描述 牛牛最近学习了C++入门课程,这门课程的总成绩计算方法是: 总成绩=作业成绩×20%+小测成绩×30%+期末考试成绩×50% 牛牛想知道,这门课程自己最终能得到多少分. 输入输出格式 输入格式: 输入文件只有1行,包含三个非负整数A.B.C,分别表示牛牛的作业成绩.小测成绩和期末考试成绩.相邻两个数之间用一个空格隔开,三项成绩满分都是100分. 输出格式: 输出文件只有1行,包含一个整数,即牛牛这门课程的总成绩,满分也是100分. 输入输出样例 输入样例#1: 复

PAT甲级1012题解——选择一种合适数据存储方式能使题目变得更简单

题目分析: 本题的算法并不复杂,主要是要搞清楚数据的存储方式(选择一种合适的方式存储每个学生的四个成绩很重要)这里由于N的范围为10^6,故选择结构体来存放对应下标为学生的id(N只有2000的范围,所以结构体开10^6其实有点浪费空间),再者对于每个学生的每种成绩的排名我们通过下面的这种方式可以巧妙得到(而且单科成绩是会出现重复的,即并列的情况): 获取排名的方法:其实很简单,由于会出现并列单科成绩的方式,且单个学生的成绩是存储在结构体里的,通过多次排序的方式去解决这道题目是不太合适的,这里用

《挑战程序设计竞赛》2.4 加工并存储数据的数据结构

这个章节一共介绍了几种数据结构:堆,二叉搜索树,并查集. 第一部分 堆. 堆的实现: int heap[maxn]; void push(int x) { int i = sz;//自己结点的编号 while(i > 0) { int p = (i - 1) / 2; if(heap[p] <= x) break; heap[i] = heap[p]; i = p; } heap[i] = x; } int pop() { int ret = heap[0];//取出优先级最高的元素 int

挑战程序设计竞赛 2.4 加工并存储数据的数据结构

[Summarize] 1.求满足条件的情况下最大化中位数可以枚举中位数再验证条件 2.对于种类并查集,可以利用拆点的方式,用x-A表示x属于A类,将种类归属关系作为节点进行运算 POJ 3614:Sunscreen /* 每个奶牛各自能够忍受的阳光强度有一个最小值和一个最大值 防晒霜的作用是让阳光照在身上的阳光强度固定为某个值 每瓶防晒霜给出固定的阳光量和防晒霜数量 每头奶牛只能用一瓶防晒霜 问最多能晒太阳的奶牛数量 */ #include <cstdio> #include <que

加工零件

#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n; int sum; int xianzai; int shengyu; struct jiagong { int a; int b; bool flag; }lj[1010]; bool mycmp(jiagong x,jiagong y) { return (x.b>y.b); } int main

加工并存储数据的数据结构

堆 一些注意点:左儿子的编号是自己的编号*2+1右儿子的编号是自己的编号*2+2父亲节点的编号是(自己的编号-1)/2 手动实现的堆,贴一段书上的代码: 1 #include <iostream> 2 3 using namespace std; 4 5 int const MAX_N=233333; 6 int heap[MAX_N]; 7 int sz,n; 8 9 void push(int); 10 int pop(void); 11 12 int main() 13 { 14 cin

CSPJ2019 加工零件

Background: 之前 $noip $死了,泥萌都说 \(noip SPFA\) 了,现在 \(noip\) 复活了,所以 \(SPFA\) 也复活了. (注:这里的 \(noip\) 跟 \(lxl\) 没有任何关系qwq Description: 原题 简化版题意: 给出无向图,\(q\) 次询问,每次给定 \(A_i, L_i\) ,设 \(dis_x\) 表示点 \(x\) 与 \(1\) 号点的距离,求 \(dis_{A_i}\) 是否与 \(dis_{L_i}\) 奇偶性相同且

《谁说菜鸟不会数据分析》数据加工

数据加工 一.数据抽取:保留原数据表中某些字段的部分信息,组成一个新字段 字段分列:截取某一字段部分信息 字段合并:几个字段合并为一个新字段 字段匹配:原数据表没有但其他数据表有的字段,有效匹配过了 字段分列 (1)菜单法 选区域--数据--分列 根据格式特点,选择合适的分隔符号 这与前面自文本导入数据的文本设置很相似. (2)函数法 left(文本,左边几个) right(文本,右边几个) 字段合并 方法一:&连接 方法二:函数concatenate(文本1,文本2,...) 字段匹配 VLO