1 条题解

  • 0
    @ 2025-8-24 22:51:29

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Genius_Star
    跟你爆了

    搬运于2025-08-24 22:51:29,当前版本为作者最后更新于2023-10-23 20:54:51,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意:

    给出一个有向图,当前在 11 号点,初始在时间 00,必须在 kk 的倍数的时间出发,且到终点的时间也必须是 kk 的倍数。

    每条边有一个边权 wiw_i,只有在当前时间 wi\ge w_i 时才可以通过,且不能在原地不动,即每一个时间点必须走一条边。

    问从 11 号点出发到 nn 号时最早的时刻。(没有方案则输出 1-1

    思路:

    因为 k100k \le 100 很小,所以我们可以从 kk 入手。

    注意到,如果我当前到达了 uu 号点,且当前时间为 pp,这条边边权为 ww,如果 p<wp < w,那么显然当前不能通过。

    但是因为如果当前可以走到这个点,那么可以晚一些 kk 的倍数的时间出发,依然可以走到这个点,则我们可以在入口处等待一些时间,使得可以通过这条边,等待时间为 wpk×k\lceil \frac{w-p}{k} \rceil \times k,即等待 wpk\lceil \frac{w-p}{k} \rceilkk 的倍数,这样就可以通过这条边了,耗费时间为 wpk×k+p\lceil \frac{w-p}{k} \rceil \times k+p

    现在通过每条边的时间更出发点为 kk 的倍数有关系,则我们可以建立以下状态:定义 disi,jdis_{i,j} 为到达 ii 号点的时间 modk\bmod k 的值为 jj 时的最短消耗时间。

    那么答案显然是 disn,0dis_{n,0}

    然后看一下转移,如果 pwp \ge w 了,那么可以直接通过,则 $dis_{v,(p+1) \bmod k} \to \min(dis_{v,(p+1) \bmod k},p+1)$。

    否则的话,令 t=wpk×k+pt=\lceil \frac{w-p}{k} \rceil \times k+p,即我们在入口处等待一些时间,使得可以走到这条边,转移为 $dis_{v,(t+1) \bmod k} \to \min(dis_{v,(t+1) \bmod k},t+1)$。

    可以运用 dijkstra 算法的思想来进行转移,每次去堆顶选取耗时最短的那个点,然后逐层松弛。

    时间复杂度为:O(n×klogn)O(n \times k \log n)

    完整代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N=10010,M=105;
    inline ll read(){
        ll x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')
              f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=(x<<1)+(x<<3)+(c^48);
            c=getchar();
        }
        return x*f;
    }
    inline void write(ll x){
    	if(x<0){
    		putchar('-');
    		x=-x;
    	}
    	if(x>9)
    	  write(x/10);
    	putchar(x%10+'0');
    }
    ll n,m,k;
    ll dis[N][M];
    bool f[N][M];
    vector<pair<ll,ll>> E[N];
    priority_queue<pair<ll,ll>,vector<pair<ll,ll>>,greater<pair<ll,ll>>> q;
    void add(ll u,ll v,ll w){
    	E[u].push_back({v,w});
    }
    void dijkstra(ll s){
    	dis[s][0]=0;
    	q.push({0,s});
    	while(!q.empty()){
    		ll u=q.top().second,p=q.top().first;
    		q.pop();
    		if(f[u][p%k])
    		  continue;
    		f[u][p%k]=1;
    		for(auto d:E[u]){
    			ll v=d.first,w=d.second,t=(p+1)%k;
    			if(p>=w)
    			  t=p;
    			else
    			  t=((w-p+k-1)/k)*k+p;
    			if(dis[v][(t+1)%k]>t+1){
    				dis[v][(t+1)%k]=t+1;
    				q.push({t+1,v});
    			}
    		}
    	}
    }
    int main(){
    	memset(dis,0x3f,sizeof(dis));
    	n=read(),m=read(),k=read();
    	for(int u,v,w,i=0;i<m;i++){
    		u=read(),v=read(),w=read();
    		add(u,v,w);
    	}
    	dijkstra(1);
    	if(!f[n][0])
    	  puts("-1");
    	else
    	  write(dis[n][0]);
    	return 0;
    }
    
    • 1

    信息

    ID
    9309
    时间
    1000ms
    内存
    500MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者