1 solutions

  • 2
    @ 2025-7-9 0:21:39
    ////V1 35分 暴力改BFS找最短路,注意环路+时间限制 
    //#include<bits/stdc++.h>
    //using namespace std;
    //const int maxn=1E4+10;
    //int n,m,k,u,v_,a,ans,vis[maxn][110];
    //struct road{
    //	int to,a;
    //};
    //struct step{
    //	int id,time;
    //};
    //vector<road> v[maxn];
    //queue<step> q;
    //int main(){
    //	cin>>n>>m>>k;
    //	for(int i=0;i<m;i++){
    //		cin>>u>>v_>>a;
    //		v[u].push_back(road{v_,a});//单向通路 
    //	}
    //	q.push(step{1, 0});
    //	vis[1][0]=true;
    //	while(q.size()){//最短路,改造BFS模板 
    //		step t=q.front();
    //		q.pop();
    //		if(t.id==n && t.time%k==0){//到达即找到最短路,本题特判到达时间是K倍数 
    //			cout<<t.time;
    //			return 0;
    //		}
    //		for(int i=0;i<v[t.id].size();i++){
    //			int d=v[t.id][i].to, ti=t.time+1;
    //			if(vis[d][ti%k])	continue;//防止重复访问陷入死循环 
    //			//注意本题可能有环!!!而且本题最短路有时间点要求!!!所以设置特殊vis 
    //			q.push(step{d, ti});
    //			vis[d][ti%k]=true;
    //		} 
    //	}
    //	cout<<"-1";//没有符合要求的到达终点的路 
    //	return 0;
    //} 
    
    ////V2 50分 加入道路开放时间的讨论,跟上面比只加了三行if(v[t.id][i].a>ti){//道路开放时间没到 
    //#include<bits/stdc++.h>
    //using namespace std;
    //const int maxn=1E4+10;
    //int n,m,k,u,v_,a,ans,vis[maxn][110];
    //struct road{
    //	int to,a;
    //};
    //struct step{
    //	int id,time;
    //};
    //vector<road> v[maxn];
    //queue<step> q;
    //int main(){
    //	cin>>n>>m>>k;
    //	for(int i=0;i<m;i++){
    //		cin>>u>>v_>>a;
    //		v[u].push_back(road{v_,a});//单向通路 
    //	}
    //	q.push(step{1, 0});//起点 
    //	vis[1][0]=true;
    //	while(q.size()){//最短路,改造BFS模板 
    //		step t=q.front();
    //		q.pop();
    //		if(t.id==n && t.time%k==0){//到达即找到最短路,本题特判到达时间是K倍数 
    //			cout<<t.time;
    //			return 0;
    //		}
    //		for(int i=0;i<v[t.id].size();i++){
    //			int d=v[t.id][i].to, ti=t.time+1;
    //			if(vis[d][ti%k])	continue;//防止重复访问陷入死循环 
    //			//注意本题可能有环!!!而且本题最短路有时间点要求!!!所以设置特殊vis 
    //			if(v[t.id][i].a>ti){//道路开放时间没到,默认这个节点晚wait时间进园子即可
    //				int wait=((v[t.id][i].a-ti)/k+1)*k;
    //				ti+=wait;
    //			}
    //			q.push(step{d, ti});
    //			vis[d][ti%k]=true;
    //		} 
    //	}
    //	
    //	cout<<"-1";//没有符合要求的到达终点的路 
    //	return 0;
    //} 
    
    /*
    思考一下不能AC的问题可能出在哪里?出在不确定的等待时间,把push进queue的各个Step的时间顺序弄乱了(可能早到某地点的时间其实更晚)。
    
            比如我们在某个时间time1走到了某个地点i,这种状态没有vis过,所以第26行往下走, 并赋值vis[i][time1 % k] = true,经过之后的若干步,最终这条路走通了,即走到n,且时间正好是k的整数倍,然后取得了一个ans。稍晚之后,我们通过另一条路,花费更少的时间time2(time2<time1)也走到了地点i,不走运的是,虽然time2<time1,但恰好time2 % k == time1 % k(这完全有可能!),而此时vis[i][time1%k]已经为true了,因此第26行就不再往下走了,而原本小Z可以以更早的时间离开景区的(如果按time2往下走的话,因为time2%k==time1%k,只要time1走得通,time2一定也走得通,而time2<time1,只是由于它push进队列比较晚,被排在后面了)。
    
            那么怎么办?我们有什么办法让time2,比time1提前被我们拿出来用。Bingo!当然要想到用优先队列priority_queue,只需要对到达时间进行排序,那么从队列中取出队首元素的时候,总是取时间最早的数据。OK,让我们对Step结构体进行从大到小排序,并把queue改成priority_queue,其他不做变动:
    */ 
    
    //V3 100分 加入道路开放时间的讨论,用priority_queue 
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1E4+10;
    int n,m,k,u,v_,a,vis[maxn][110];
    struct road{
    	int to,a;
    };
    struct step{
    	int id,time;
    	bool operator < (const step& t) const{
    		return time > t.time;//改priority_queue可以按到达时间排序 ,默认是小顶堆,所以重载< 改成大顶堆 
    	}
    };
    vector<road> v[maxn];
    priority_queue<step> q;
    int main(){
    //	freopen("P9751_21.in", "r", stdin);
    	cin>>n>>m>>k;
    	for(int i=0;i<m;i++){
    		cin>>u>>v_>>a;
    		v[u].push_back(road{v_,a});
    	}
    	q.push(step{1, 0});
    	while(q.size()){ 
    		step t=q.top();
    		q.pop();
    		if(t.id==n && t.time%k==0){//仍然是到达即找到最短路,本题特判到达时间是K倍数(0也算) 
    			cout<<t.time;
    			return 0;
    		}
    		if(vis[t.id][t.time%k])	continue;
    		//按时间先访问的元素先vis标记。如果在for循环里就判断,由于wait等待时间差异,可能先到达的反而先因为后到达的vis排除 
    		vis[t.id][t.time%k]=true; 
    		for(int i=0;i<v[t.id].size();i++){
    			int d=v[t.id][i].to, ti=t.time+1;
    			if(v[t.id][i].a>=ti){//要取=,这个临界点还没开放道路  
    				int wait=((v[t.id][i].a-ti)/k+1)*k;
    				ti+=wait;
    			} 
    			q.push(step{d, ti});
    		} 
    	}
    	
    	cout<<"-1";
    	return 0;
    } 
    /*
    input1
    9 15 97
    1 1 990149
    6 4 393083
    4 7 171280
    6 7 635660
    8 6 123113
    1 2 384925
    6 7 507533
    8 6 416969
    3 4 975110
    2 5 575466
    2 4 72458
    7 9 923003
    5 3 590414
    4 8 733761
    7 5 440313
    
    output1
    923052
    
    input2
    5 5 1
    1 2 0
    2 3 0
    3 4 0
    4 5 0
    1 5 1
    
    output2
    2
    */
    
    //另一种写法,仅仅是改变结构体,将time分成wait和dis记录,便于向难题扩展 
    //#include<bits/stdc++.h>
    //using namespace std;
    //const int maxn=1E4+10;
    //int n,m,k,u,v_,a,vis[maxn][110];
    //struct road{
    //	int to,a;
    //};
    //struct step{
    //	int id,wait,dis;
    //	bool operator < (const step& t) const{
    //		return wait+dis > t.wait+t.dis;//记录门口等待时间wait和路上距离时间dis,题目对进入离开时间都有要求 
    //	}
    //};
    //vector<road> v[maxn];
    //priority_queue<step> q;
    //int main(){
    //	freopen("P9751_21.in", "r", stdin);
    //	cin>>n>>m>>k;
    //	for(int i=0;i<m;i++){
    //		cin>>u>>v_>>a;
    //		v[u].push_back(road{v_,a});
    //	}
    //	q.push(step{1, 0, 0});
    //	while(q.size()){ 
    //		step t=q.top();
    //		q.pop();
    //		if(t.id==n && t.dis%k==0){//题意是保证进入时间wait和离开时间wait+dis都要是k倍数,所以保证wait和dis是k倍数即可
    //			cout<<t.wait + t.dis;
    //			return 0;
    //		}
    //		if(vis[t.id][t.dis%k])	continue;
    //		//按时间先访问的元素先vis标记。如果在for循环里就判断,由于wait等待时间差异,可能先到达的反而先因为后到达的vis排除 
    //		vis[t.id][t.dis%k]=true; 
    //		for(int i=0;i<v[t.id].size();i++){
    //			int d=v[t.id][i].to, time=t.wait+t.dis+1, wait=t.wait, dis=t.dis+1;
    //			if(v[t.id][i].a>=time){//要取=,这个临界点还没开放道路 
    //				int need=((v[t.id][i].a-time)/k+1)*k;
    //				wait+=need;//保证wait一直是k的倍数 
    //			} 
    //			q.push(step{d, wait, dis});
    //		} 
    //	}
    //	
    //	cout<<"-1";
    //	return 0;
    //}
    
    • 1

    Information

    ID
    9092
    Time
    1000ms
    Memory
    500MiB
    Difficulty
    4
    Tags
    # Submissions
    17
    Accepted
    6
    Uploaded By