ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【做题笔记】[CSP-J2019]洛谷P5663加工零件

2020-04-02 09:00:10  阅读:355  来源: 互联网

标签:P5663 洛谷 int 偶数 vis 阶段 零件 J2019 dis


很遗憾2019年没学图论。

否侧这题至少能拿60分。

我谔谔。


首先,一个很容易发现的想法是,设 \(vis_{u,s}\) 表示 \(u\) 号工人是否需要生产一个 \(s\) 阶段的零件,那么一个高达 60 分的程序一下就出来了:

#include <iostream>
#include <stdio.h>
#include <string.h>

int n, m, q, ver[100001], head[1000001], tot, nxt[1000001],vis[1005][1005];

void add(int u, int v)
{
    ver[++tot]=v; nxt[tot]=head[u]; head[u]=tot;
}

void dfs(int u, int s)
{
    if(s==-1 || vis[u][s]) return ;
    //如果 s 为 -1 或 u 已经需要生产一个 s 阶段的零件,直接返回
    vis[u][s]=1;
    //否则 u 工人需要生产一个 s 阶段的零件
    
    for(int i=head[u];i;i=nxt[i])
    {
        int y=ver[i];
        dfs(y,s-1); //与之相连的工人都需要生产一个 s-1 阶段的零件
    }
}

int main()
{
    std::cin>>n>>m>>q;
    for(int i=1;i<=m;i++)
    {
        int u, v;
        std::cin>>u>>v;
        add(u, v);
        add(v, u);
    }

    while(q--)
    {
        int a, L;
        memset(vis, 0, sizeof(vis));
        std::cin>>a>>L;
        dfs(a, L);
        if(vis[1][0]) printf("Yes\n");
        //如果1号工人需要生产一个0阶段的零件就输出Yes
        else printf("No\n");
        //否则输出No
    }

    return 0;
}

接下来考虑正解。注意到一个性质:如果某两个点存在一条传送带,那么这两个点可以互相要零件。把这个性质推广一下:如果1号和另一个工人有一个传送带,那么她们可以互相要零件

例如下图,2号要生产一个30阶段的零件,那么她就需要向1号要一个29阶段的零件:

8816VH.png

现在,1号要生产一个29阶段的零件,那么她就要向2号要一个28号的零件!

8817ZQ.png

现在,2号要生产一个28阶段的零件,那么她就要向1号要一个27号的零件;1号要生产一个27阶段的零件,那么她就要像2号要一个26阶段的零件......以此类推。

那么我们现在把这个性质稍微抽象一下,也就是说,我们判断1号是否需要向 \(a\) 提供0阶段的零件,只需要看1号是否需要向与之相连的某一号提供0阶段的零件即可!(废话)

接着我们发现:1号点需要向与之相邻(有边)的某一点提供0阶段的零件,当且仅当与之相邻的那一点需要生产一个奇数的零件。

很容易证明其正确性:如果与1号相邻的某一点要生产一个奇数阶段的零件,那么她就必须向1号要一个偶数阶段的零件。而0恰好是一个偶数!

而之所以要大于等于是因为,如果小于,那么就没1号啥事了,在到达一号之前就被别的零件垄断了!

然后我们仔细思考易得:

  1. 如果1一定要向 \(a\) 提供一个0阶段的零件,而 \(a\) 需要一个偶数阶段的零件,那么 1~a 的路径中一定存在一条长度为偶数且大于等于这个阶段零件的大小;
  2. 如果1一定要向 \(a\) 提供一个0阶段的零件,而 \(a\) 需要一个奇数阶段的零件,那么 1~a 的路径中一定存在一条长度为奇数且大于等于这个阶段零件的大小。

以第一种情况为例解释一下:如果 \(a\) 需要一个偶数阶段的零件,那么只有当某条路径的长度(默认一条边的长度为1)为偶数时,与1号相连的某一点需要生产的零件才为奇数,1号点才要提供一个0阶段的零件!

第二种情况同理。

那么我们是不是真的需要去暴力找边呢?其实不需要。

因为如果有一条最短的路径满足条件,那么与其性质相同的必然也成立(所谓性质相同就是上面提到的两点,因为满足条件的很可能不止一种路径,这时候只要找最短的那条即可!)!

此时,我们就只需要设 \(dis_{u,1}\) 和 \(dis_{u,0}\) 分别表示 1~u 的奇数最短路径和偶数最短路径,然后跑一遍 SPFA ,求出这个最短路,然后判断是否满足即可。一些细节见代码:

#include <iostream>
#include <stdio.h>
#include <queue>

using namespace std;

int n, m, q, tot, head[1000001], nxt[1000001], ver[1000001];
int dis[100001][3], vis[1000010][3];

void add(int u, int v)
{
    ver[++tot]=v; nxt[tot]=head[u]; head[u]=tot;
}

void spfa()
{
    queue<int> q, p;
    //q队列表示点
    //p队列表示奇数或偶数
    for(int i=1;i<=n;i++) dis[i][1]=dis[i][0]=233333333;
    //一开始全部搞成无穷大
    dis[1][0]=0;
    //第一个点本身就是偶数,所以偶数最短路径为0
    //奇数最短路径显然不存在
    q.push(1);
    p.push(0); //一开始push 1 也是可以的
    while(!q.empty()&&!p.empty())
    //必须要两个队列均不为空
    {
        int u=q.front(); q.pop();
        int s=p.front(); p.pop();
        vis[u][s]=0;
        for(int i=head[u];i;i=nxt[i])
        {
            int y=ver[i];
            if(dis[y][0]>dis[u][1]+1)
            {
                dis[y][0]=dis[u][1]+1;
                //偶数边可以通过奇数边+1得到
                if(!vis[y][0])
                {
                    vis[y][0]=1;
                    q.push(y);
                    p.push(0);
                }
            }
            //处理偶数最短路
            if(dis[y][1]>dis[u][0]+1)
            {
                dis[y][1]=dis[u][0]+1;
                //奇数边可以通过偶数边+1得到
                if(!vis[y][1])
                {
                    vis[y][1]=1;
                    q.push(y);
                    p.push(1);
                }
            }
            //处理奇数最短路
        }
    }
}

int main()
{
    cin>>n>>m>>q;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
        //无向图,需要反向建边
    }

    spfa();

    if(head[1]==0) dis[1][0]=233333333;
    //如果1号是孤立点那就也没有路径

    while(q--)
    {
        int a,L;
        cin>>a>>L;
        if(L>=dis[a][L%2]) printf("Yes\n");
        //这里用到了一个技巧判断是需要奇数最短路还是偶数最短路,即
        //偶数%2为0,奇数%2为1,所以我们的dis数组才那样表示
        else printf("No\n");
    }

    return 0;
}

标签:P5663,洛谷,int,偶数,vis,阶段,零件,J2019,dis
来源: https://www.cnblogs.com/BlueInRed/p/12617517.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有