1. 程式人生 > >NOIP模擬 有向無環圖(玄學建圖+最短路)

NOIP模擬 有向無環圖(玄學建圖+最短路)

內網傳送門

【題目分析】

SPFA竟然有人亂搞A了?orz(蒟蒻亂搞只有40pts qwq)

很巧妙的建圖思路,將每條路徑視為一個點,從一條路徑i到達另一條路徑j,如果w[i]<w[j],那麼會產生w[j]-w[i]的費用,否則不會產生任何費用。

所以考慮將所有邊存下,然後每個點遍歷一遍,將邊排序,從小到大依次加費用為0的邊,再從大到小加費用為w[i]-w[i-1]的邊,最後在圖上跑迪傑斯特拉即可。

【程式碼~】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;
const int MAXN=2e5+50;
const int MAXM=4e5+50;

int n,m,ecnt=1;
int head[MAXN],vis[MAXM],tot;
int nxt[MAXM],to[MAXM],w[MAXM];
ll dis[MAXM];
vector<pii>edge[MAXM];
priority_queue< pii,vector<pii>,greater<pii> >q;
struct Edge{
    int id,w;
    Edge(){}
    Edge(int x,int z):id(x),w(z){} 
    friend inline bool operator <(const Edge &a,const Edge &b){
        return a.w<b.w;
    }
}e[MAXM];

int Read(){
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

void add(int x,int y,int z){
    nxt[++ecnt]=head[x];
	head[x]=ecnt;
	to[ecnt]=y;
	w[ecnt]=z;
}

void dijkstra(){
    for(int i=2;i<=ecnt;i++) 
	  dis[i]=2e18;
    for(int i=head[1];i;i=nxt[i]){
        dis[i]=w[i];
		q.push(make_pair(dis[i],i));
    }
    while(!q.empty()){
        if(vis[q.top().second]){
			q.pop();
			continue;
		}
        int u=q.top().second;
		q.pop();
		vis[u]=1;
        for(int i=edge[u].size()-1;i>=0;i--){ 
            int v=edge[u][i].first;
			int w=edge[u][i].second;
            if(vis[v])
			  continue;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                q.push(make_pair(dis[v],v));
            }
        }
    }
}

int main(){
    n=Read(),m=Read();
    for(int i=1;i<=m;i++){
        int x=Read(),y=Read(),z=Read();
        add(x,y,z);add(y,x,z);
    }
    for(int u=2;u<n;u++){
    	tot=0;
        for(int i=head[u];i;i=nxt[i])
            e[++tot]=Edge(i,w[i]);
        sort(e+1,e+tot+1);
        for(int i=1;i<=tot;i++){
            if(i!=1)
			  edge[e[i].id].push_back(make_pair(e[i-1].id,0));
            if(i!=tot)
			  edge[e[i].id].push_back(make_pair(e[i+1].id,e[i+1].w-e[i].w));
            edge[e[i].id^1].push_back(make_pair(e[i].id,e[i].w));
        }
    }
    dijkstra();
    ll ans=2e18;
    for(int i=head[n];i;i=nxt[i])
        ans=min(ans,dis[i^1]+w[i]);
    cout<<ans;
    return 0;
}