2019CSP-J组题目-加工零件

凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇。
工厂里有 n 位工人,工人们从 1∼n 编号。
某些工人之间存在双向的零件传送带。
保证每两名工人之间最多只存在一条传送带。
如果 x号工人需要生产一个被加工到第 L(L>1) 阶段的零件,则所有与 x号工人有传送带直接相连的工人,都需要生产一个被加工到第 L−1 阶段的零件(但 x 号工人自己无需生产第 L−1 阶段的零件)。
如果 x 号工人需要生产一个被加工到第 1 阶段的零件,则所有与 x号工人有传送带直接相连的工人,都需要为 x 号工人提供一个原材料。
轩轩是 1 号工人。
现在给出 q 张工单,第 i 张工单表示编号为 ai 的工人想生产一个第 Li 阶段的零件。
轩轩想知道对于每张工单,他是否需要给别人提供原材料。
他知道聪明的你一定可以帮他计算出来!
输入格式
第一行三个正整数 n,m 和 q,分别表示工人的数目、传送带的数目和工单的数目。
接下来 m 行,每行两个正整数 u 和 v,表示编号为 u 和 v 的工人之间存在一条零件传输带。保证 u≠v。
接下来 q 行,每行两个正整数 a 和 L,表示编号为 a 的工人想生产一个第 L 阶段的零件。
输出格式
共 q 行,每行一个字符串 “Yes” 或者 “No”。如果按照第 i张工单生产,需要编号为 1 的轩轩提供原材料,则在第 i 行输出 “Yes”;否则在第 i 行输出 “No”。注意输出不含引号。
数据范围
1≤u,v,a≤n
测试点 1∼4,1≤n,m≤1000,q=3,L=1。
测试点5∼8,1≤n,m≤1000,q=3,1≤L≤10。
测试点 9∼12,1≤n,m,L≤1000,1≤q≤100。
测试点 13∼16,1≤n,m,L≤1000,1≤q≤105。
测试点 17∼20,1≤n,m,q≤105,1≤L≤109。
输入样例1:
3 2 6
1 2
2 3
1 1
2 1
3 1
1 2
2 2
3 2
输出样例1:
No
Yes
No
Yes
No
Yes
输入样例2:
5 5 5
1 2
2 3
3 4
4 5
1 5
1 1
1 2
1 3
1 4
1 5
输出样例2:
No
Yes
No
Yes
Yes
样例解释
样例#1:

编号为 1 的工人想生产第 1 阶段的零件,需要编号为 2 的工人提供原材料。
编号为 2 的工人想生产第 1 阶段的零件,需要编号为 1 和 3 的工人提供原材料。
编号为 3 的工人想生产第 1 阶段的零件,需要编号为 2 的工人提供原材料。
编号为 1 的工人想生产第 2 阶段的零件,需要编号为 2 的工人生产第 1 阶段的零件,需要为编号 1 和 3 的工人提供原材料。
编号为 2 的工人想生产第 2 阶段的零件,需要编号为 1 和 3 的工人生产第 1 阶段的零件,他/她们都需要编号为 2 的工人提供原材料。
编号为 3 的工人想生产第 2 阶段的零件,需要编号为 2 的工人生产第 1 阶段的零件,需要编号为 1 和 3 的工人提供原材料。
样例#2:

编号为 1 的工人想生产第 1 阶段的零件,需要编号为 2 和 5 的工人提供原材料。
编号为 1 的工人想生产第 2 阶段的零件,需要编号为 2 和 5 的工人生产第 1 阶段的零件,需要编号为 1,3,4 的工人提供原材料。
编号为 1 的工人想生产第 3 阶段的零件,需要编号为 2 和 5 的工人生产第 2 阶段的零件,需要编号为 1,3,4 的工人生产第 1 阶段的零件,需要编号为 2,3,4,5 的工人提供原材料。
编号为 1 的工人想生产第 4 阶段的零件,需要编号为 2 和 5 的工人生产第 3 阶段的零件,需要编号为 1,3,4 的工人生产第 2 阶段的零件,需要编号为 2,3,4,5 的工人生产第 1 阶段的零件,需要全部工人提供原材料。
编号为 1 的工人想生产第 5 阶段的零件,需要编号为 2 和 5 的工人生产第 4 阶段的零件,需要编号为 1,3,4 的工人生产第 3 阶段的零件,需要编号为 2,3,4,5 的工人生产 第 2 阶段的零件,需要全部工人生产第 1 阶段的零件,需要全部工人提供原材料。

 题解:
 

针对题意,原材料相当于第0阶段的零件、我们先假设1号工人轩轩与其他工人之间没有传送带的情况,那么显然,这种情况下,轩轩无法生产任何零件和原料,也不需要给其它工人提供原材料,答案显然是NO。

假设现在1号工人轩轩和i号工人有连边(双向传送带),那么当i号工人需要生产第1、3、5、7……2k+1阶段的零件的时候,1号工人轩轩分别需要提供第0(原材料)、2、4、6……2k阶段的零件,紧接着i号工人要提供给1号工人轩轩(总数量-2个)奇数阶段的零件,我们发现针对每一个奇数阶段的零件,轩轩都需要提供原材料。

当i号工人想生产偶数阶段的零件时,轩轩需要提供奇数阶段的零件,而如果1号工人轩轩需要偶数阶段的零件,那么i号工人需要提供奇数阶段的零件。
我们将之扩大为一条链:

假设i号工人需要生产 L(L>0)阶段的零件

那么只要i->1之间存在一条长度<=L并且和L的奇偶性相同的路径,1号工人就必须生产原材料。

因此:对于一条双向边 1<--->U 我们将每个点1、U分别拆成两的点(奇点和偶点),边分解为交叉边,生成一张新图,对于新图:

所有从1(0)走向u(0)的路径,对应在原图中就是一条L为偶数的路径。

所有从1(0)走向u(1)的路径,对应在原图中就是一条L为奇数的路径。

为了降低复杂度,我们可以查找:
所有从1(0)走向u(0)的最短路径dist[u][0],所有从1(0)走向u(1)的最短路径dist[u][1]。问题就转化为单源最短路问题:

对于每次查询的A和 L

我们只需要做如下判断
L是偶数:则只要L>=dist[A][0];

L是奇数:则只要L>=dist[A][1];

AC代码:

1.普通bfs

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
# define N 100005
# define M 200005
int n, m, query;
int head[N],ver[M],Next[M],tot=-1;
int dist[N][2];
queue<pair<int ,int> > Q;
void ADD(int x,int y)
{
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
void bfs()
{
    int x,y,t;
    memset(dist, 0x3f, sizeof(dist));//初始化
    Q.push(make_pair(1,0));
    dist[1][0] = 0;
    while (Q.size())
    {
        int x=Q.front().first,t = Q.front().second;
        Q.pop();
        for (int i = head[x];~i;i=Next[i])
        {
            y= ver[i];
            if (dist[y][t^1]>dist[x][t]+1)
            {
                dist[y][t^1]=dist[x][t]+1;
                Q.push(make_pair(y,t^1));
            }
        }
    }
}
int main()
{
    int x,y;
    scanf("%d%d%d", &n, &m, &query);
    memset(head, -1, sizeof(head));
    for (int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);
        ADD(x,y);
        ADD(y,x);
    }
    bfs();
    while (query--)
    {
        int A, B;
        scanf("%d%d", &A, &B);
        if (A== 1 && head[1]==-1)puts("No");
        else if (dist[A][B&1] <= B) puts("Yes");
        else puts("No");
    }
    return 0;
}

2.dijkstra

#include <cstdio>
#include <cstring>
#include <iostream>
# include<queue>
#include <algorithm>
using namespace std;
# define N 100005
# define M 200005
int n, m, query;
int head[N],ver[M],Next[M],tot=-1;
int dist[N][2];
bool vis[N][2];
priority_queue<pair<int ,pair<int,int> > >Q;// 最短路径 <点,状态>
void ADD(int x,int y)
{
    ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
    ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
}
void dijkstra()
{
    int x,y,t;
    memset(dist, 0x3f, sizeof(dist));//初始化
    dist[1][0] = 0;
    memset(vis,0,sizeof(vis));
    Q.push(make_pair(0,make_pair(1,0)));
    while(Q.size())
    {
        x=Q.top().second.first;
        t=Q.top().second.second;
        Q.pop();
        if(vis[x][t])continue;
        vis[x][t]=1;
        for(int i=head[x];~i;i=Next[i])
        {
            y=ver[i];
            if(dist[y][t^1]>dist[x][t]+1)
            {
                dist[y][t^1]=dist[x][t]+1;
                Q.push(make_pair(-dist[y][t^1],make_pair(y,t^1)));
            }
        }
    }
}
int main()
{
    int x,y;
    scanf("%d%d%d", &n, &m, &query);
    memset(head, -1, sizeof(head));
    for (int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);
        ADD(x,y);
    }
    dijkstra();
    while (query--)
    {
        int A, B;
        scanf("%d%d", &A, &B);
        if (A== 1 && head[1]==-1)puts("No");
        else if (dist[A][B&1] <= B) puts("Yes");
        else puts("No");
    }
    return 0;
}

 3.spfa

#include <cstdio>
#include <cstring>
#include <iostream>
# include<queue>
#include <algorithm>
using namespace std;
# define N 100005
# define M 200005
int n, m, query;
int head[N],ver[M],Next[M],tot=-1;
int dist[N][2];
bool vis[N][2];
queue<pair<int ,int> >Q;//  <点,状态>
void ADD(int x,int y)
{
    ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
    ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
}
void spfa()
{
    int x,y,t;
    memset(dist, 0x3f, sizeof(dist));//初始化
    dist[1][0] = 0;
    memset(vis,0,sizeof(vis));
    vis[1][0]=1;
    Q.push(make_pair(1,0));
    while(Q.size())
    {
        x=Q.front().first;
        t=Q.front().second;
        Q.pop();
        vis[x][t]=0;
        for(int i=head[x];~i;i=Next[i])
        {
            y=ver[i];
            if(dist[y][t^1]>dist[x][t]+1)
            {
                dist[y][t^1]=dist[x][t]+1;
                if(!vis[y][t^1])
                Q.push(make_pair(y,t^1));
            }
        }
    }
}
int main()
{
    int x,y;
    scanf("%d%d%d", &n, &m, &query);
    memset(head, -1, sizeof(head));
    for (int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);
        ADD(x,y);
    }
    spfa();
    while (query--)
    {
        int A, B;
        scanf("%d%d", &A, &B);
        if (A== 1 && head[1]==-1)puts("No");
        else if (dist[A][B&1] <= B) puts("Yes");
        else puts("No");
    }
    return 0;
}

 

### 关于 CSP-J 2019 加工零件问题的解析 #### 题目描述 在一个工厂里,有 n 台机器用于加工 m 种不同的零件。每种零件都需要经过一系列特定顺序的操作才能完成。给定每台机器可以执行哪些操作以及每个零件所需的具体操作序列,计算最少需要多少天能够完成所有零件加工。 #### 数据范围 - \(n \leq 50\) 表示机器数量 - \(m \leq 50\) 表示零件种类数 - 每个零件最多包含 50 个工序[^1] #### 思路分析 此题属于经典的调度类动态规划题目。核心在于如何合理安排不同类型的零件在各台机器上依次进行处理的时间表,使得总的耗时最小化。主要考虑以下几个方面: 1. **状态定义** 定义 `dp[i][j]` 表示前 i 类零件,在第 j 天结束时所能达到的最大进度(即已经完成了多少道工序)。这里需要注意的是,“最大进度”并不意味着一定要连续做完某件物品的所有工作;而是指到目前为止累计完成的工作量总和。 2. **转移方程** 对于每一个新的零件 k 和每一天 d 来说,如果当前这台机器可以在这一天做这个零件的一个新阶段,则更新 dp 数中的对应位置: ```python if can_process(machine, part_k, day_d): dp[k][d] = max(dp[k][d], min(dp[p][day_before(d)] + process_time(part_k))) ``` 3. **初始条件与边界情况** 初始化时假设第一天没有任何东西被制造出来,因此所有的 dp 值都设为零。对于那些无法立即开始生产的项目来说,它们的状态应该保持不变直到满足启动的前提条件为止。 4. **最终结果获取** 查找最后一列中最大的数值作为答案返回即可,因为这意味着整个生产周期中最晚的一批货物也已经被送出了生产线。 ```cpp #include <iostream> using namespace std; const int MAXN = 55; int n, m; // number of machines and parts respectively bool machine_can_do[MAXN][MAXN]; // whether the ith machine can do the jth operation vector<int> operations[MAXN]; // list of required operations for each type of part int dp[MAXN][MAXN]; // Function to check feasibility... void solve() { memset(dp, 0, sizeof(dp)); // Fill DP table according to rules mentioned above } int main(){ cin >> n >> m; // Read input data ... solve(); } ``` 通过上述方法,可以有效地解决这个问题并找到最优解方案。值得注意的是实际编程实现过程中还需要注意细节上的优化以确保程序能够在规定时间内给出正确解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值