【分層圖/ 變形最短路】2018 ACM-ICPC 南京網路賽
阿新 • • 發佈:2019-01-24
題意:
給出一張有向圖,能夠把最多k條邊的權值變為零,問從點1到點n的最短距離是多少。
題解一:
分層圖。
建立k張一模一樣的有向圖,層與層之間用權值為零的邊相連。
層與層之間的跳躍就是代表選擇了一條邊權值變為零。
跑一遍迪傑斯特拉,輸出最後一層的點n距離就是答案。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=5e6+7; ll n,m,k; struct Edge{ ll v,w,nxt; Edge(ll v=0,ll w=0,ll nxt=0):v(v),w(w),nxt(nxt){} }e[N]; ll edn,p[N]; void add(ll u,ll v,ll w){ e[++edn]=Edge(v,w,p[u]);p[u]=edn; } struct Node{ ll id,w; Node(ll id,ll w):id(id),w(w){} bool operator<(const Node &a)const{ return w>a.w; } }; ll vis[N],dis[N]; void dij(){ priority_queue<Node>q; memset(dis,125,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[1]=0; q.push(Node(1,0)); while(!q.empty()){ ll u=q.top().id;q.pop(); vis[u]=1; for(ll i=p[u];~i;i=e[i].nxt){ ll v=e[i].v; if(vis[v]) continue; if(dis[v]-dis[u]>e[i].w){ dis[v]=dis[u]+e[i].w; q.push(Node(v,dis[v])); } } } } int main() { ll t; scanf("%lld",&t); while(t--){ scanf("%lld%lld%lld",&n,&m,&k); memset(p,-1,sizeof(p));edn=-1; ll u,v,w; for(ll i=1;i<=m;i++){ scanf("%lld%lld%lld",&u,&v,&w); for(ll j=0;j<=k;j++){ add(u+n*j,v+n*j,w); if(j!=k) add(u+n*j,v+n*(j+1),0); } } dij(); printf("%lld\n",dis[n*(k+1)]); } return 0; }
題解二:
類似dp的思想,把最短路的dis陣列開兩維,dis[i][j]表示走到第i個,改變了j個權值。
每次轉移進行兩次的轉移即可。比上面的會快很多。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=5e5+7; ll n,m,k; struct Edge{ ll v,w,nxt; Edge(ll v=0,ll w=0,ll nxt=0):v(v),w(w),nxt(nxt){} }e[N]; ll edn,p[N]; void add(ll u,ll v,ll w){ e[++edn]=Edge(v,w,p[u]);p[u]=edn; } struct Node{ ll id,sta,w; Node(ll id,ll sta,ll w):id(id),sta(sta),w(w){} bool operator<(const Node &a)const{ return w>a.w; } }; ll vis[N][20],dis[N][20]; void dij(){ priority_queue<Node>q; memset(dis,125,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[1][0]=0; q.push(Node(1,0,0)); while(!q.empty()){ Node t=q.top();q.pop(); ll u=t.id; vis[u][t.sta]=1; for(ll i=p[u];~i;i=e[i].nxt){ ll v=e[i].v; if(vis[v][t.sta]) continue; if(t.sta<k&&dis[v][t.sta+1]>t.w){ dis[v][t.sta+1]=t.w; q.push(Node(v,t.sta+1,t.w)); } if(dis[v][t.sta]-dis[u][t.sta]>e[i].w){ dis[v][t.sta]=dis[u][t.sta]+e[i].w; q.push(Node(v,t.sta,dis[v][t.sta])); } } } } int main() { ll t; scanf("%lld",&t); while(t--){ scanf("%lld%lld%lld",&n,&m,&k); memset(p,-1,sizeof(p));edn=-1; ll u,v,w; for(ll i=1;i<=m;i++){ scanf("%lld%lld%lld",&u,&v,&w); add(u,v,w); } dij(); printf("%lld\n",dis[n][k]); } return 0; }