「JOI 2021 Final」機器人
阿新 • • 發佈:2021-11-04
「JOI 2021 Final」機器人
首先走一條路且有其他路的顏色與這條路相同,有兩種情況。
- 把這條路道路的顏色改變
- 把其他與這條路顏色相同的路的顏色改變。
又因為我們有 \(M\) 種顏色,一共只有 \(M\) 條路,所以我們可以做到將一條邊塗改成一種獨一無二的顏色。
由於重複經過一個點不可能成為最優方案,所以我們可以直接這麼建邊跑一段最短路。
但是這麼跑出來的答案是偏大的。因為假設我們通過 \(1\) 方式轉移,那麼下一次走相同顏色的邊就可以少改變一條邊的顏色。
而如果通過 \(2\) 方式轉移,則沒有影響,因為如果通過 \(2\) 方式改變邊的顏色會對之後產生影響的話,不如直接走會產生影響的那條邊,這樣更優。
所以我們還得建邊,對於點 \(u,v\),我們要新建邊來滿足這樣的需求:從 \(u\) 走顏色為 \(c\) 的邊到 \(v\),然後在 \(v\) 接著走顏色為 \(c\) 的邊,並且從 \(u\) 到 \(v\) 是通過 \(1\) 方式,從 \(v\) 走出是通過 \(2\) 方式。
建好新邊後再跑一遍最短路就行了,我們可以採用虛點的策略去建新邊,那麼點數不超過 \(n+2\times m\),邊數不超過 \(6\times m\)。
程式碼如下:
路漫漫其修遠兮,吾將上下而求索。#include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN = 6e5+5; const ll INF = 1e17; int n,m; ll dis[MAXN],cnt[MAXN]; struct E { int to;ll w;int c; }; vector <E> g[MAXN],e[MAXN]; struct node { int p;ll dis; bool operator < (const node&x)const { return dis>x.dis; } }; bool vis[MAXN]; void dij() { memset(dis,0x3f,sizeof dis); memset(vis,0,sizeof vis); priority_queue <node> q; q.push(node{1,0}); dis[1]=0; while(!q.empty()) { node now=q.top(); q.pop(); int p=now.p; if(vis[p]) continue; vis[p]=1; for(int i=0;i<e[p].size();++i) { int to=e[p][i].to;ll w=e[p][i].w; if(dis[to]>dis[p]+w) { dis[to]=dis[p]+w; q.push(node{to,dis[to]}); } } } if(dis[n]>INF) printf("-1\n"); else printf("%lld\n",dis[n]); } map <int,int> mp[MAXN]; void dfs(int p) { vis[p]=1; for(int i=0;i<g[p].size();++i) cnt[g[p][i].c]+=g[p][i].w; for(int i=0;i<g[p].size();++i) { int to=g[p][i].to; e[p].push_back(E{to,cnt[g[p][i].c]>g[p][i].w?min(g[p][i].w,cnt[g[p][i].c]-g[p][i].w):0,0}); e[p].push_back(E{mp[to][g[p][i].c],0,0}); e[mp[p][g[p][i].c]].push_back(E{to,cnt[g[p][i].c]-g[p][i].w,0}); } for(int i=0;i<g[p].size();++i) cnt[g[p][i].c]=0; for(int i=0;i<g[p].size();++i) { int to=g[p][i].to; if(vis[to]) continue; dfs(to); } } int main() { // freopen("robot.in","r",stdin); // freopen("robot.out","w",stdout); scanf("%d %d",&n,&m); int Node=n; for(int i=1;i<=m;++i) { int u,v,c;ll p; scanf("%d %d %d %lld",&u,&v,&c,&p); g[u].push_back(E{v,p,c}); g[v].push_back(E{u,p,c}); if(!mp[u].count(c)) mp[u][c]=++Node; if(!mp[v].count(c)) mp[v][c]=++Node; } dfs(1); dij(); return 0; }