BZOJ5047 空间传送装置 2017年9月月赛 最短路 SPFA

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ5047


题意概括

  概括??~别为难语文做一题错两题的我了……

  


题解

  我们发现,对于某一种装置,有c种不同的时刻的花费是不同的。

  对于s mod c不同的,花费也不一定相同。

  但是有一点是一定可以确定的:对于s1<s2,从如果可以从s1开始,一定不比s2差,因为s1可以转移到s2时刻。

  我考虑预处理一个数组gt(变量名瞎捏的),gt[i][j]表示第i个机器,从第j个时刻出发,最快可以在哪个时刻到。其中i<=m,0<=j<c[i]。

  那么显然有一个大力的m*c2的算法来求gt。注意,如果你等待c秒及以上,则一定是亏的。

  然而,实际上,我们只需要大力求解gt[i][c-1]即可,对于gt[i][j](0<=j<c-1),我们可以考虑有两种选择:一种是当前时刻转移,一种是当前时刻不转移。显然,当前时刻不转移,答案就是gt[i][j+1],当前时刻转移的话,可以直接算。所以复杂度去掉了一个2000.

  当然,用O(m*c2)的算法还是可以过去的,而O(m*c)当然可以更快。

  接下来就是大力跑SPFA就可以了。

  注意输出时候的-1.


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N=100000+5,M=50+5,E=200000+5,T=2000+5,Inf=700000000;
struct Gragh{
    int cnt,x[E],y[E],z[E],nxt[E],fst[N];
    void set(){
        cnt=0;
        memset(fst,0,sizeof fst);
    }
    void add(int a,int b,int c){
        x[++cnt]=a,y[cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
    }
}g;
struct Mac{
    int a,b,c,d;
}ma[M];
int n,m,e,s,gt[M][T],dis[N];
bool f[N];
queue <int> q;
int main(){
    scanf("%d%d%d%d",&n,&m,&s,&e);
    for (int i=1;i<=m;i++){
        scanf("%d%d%d%d",&ma[i].a,&ma[i].b,&ma[i].c,&ma[i].d);
        int a=ma[i].a,b=ma[i].b,c=ma[i].c,d=ma[i].d;
        for (int j=0;j<c;j++)
            gt[i][j]=1e9;
        for (int j=0;j<c;j++){
            int now=c-1+j;
            gt[i][c-1]=min(gt[i][c-1],now+(a*now+b)%c+d);
        }
        for (int j=c-2;j>=0;j--)
            gt[i][j]=min(gt[i][j+1],j+(a*j+b)%c+d);
    }
    g.set();
    for (int i=1,a,b,c;i<=e;i++){
        scanf("%d%d%d",&a,&b,&c);
        g.add(a,b,c);
    }
    for (int i=1;i<=n;i++)
        dis[i]=1e9;
    memset(f,0,sizeof f);
    dis[1]=s;
    while (!q.empty())
        q.pop();
    q.push(1);
    f[1]=1;
    while (!q.empty()){
        int x=q.front();
        q.pop();
        f[x]=0;
        for (int i=g.fst[x];i;i=g.nxt[i]){
            int y=g.y[i],z=g.z[i],mo=dis[x]%ma[z].c;
            int gtime=dis[x]-mo+gt[z][mo];
            if (dis[y]>gtime){
                dis[y]=gtime;
                if (!f[y]){
                    f[y]=1;
                    q.push(y);
                }
            }
        }
    }
    for (int i=2;i<=n;i++)
        if (dis[i]<Inf)
            printf("%d\n",dis[i]-s);
        else
            printf("-1\n");
    return 0;
}

  

posted @   zzd233  阅读(419)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?

点击右上角即可分享
微信分享提示