1. 程式人生 > 實用技巧 >2020牛客多校(五) Portal(dp)

2020牛客多校(五) Portal(dp)

雖然看上去需要維護兩個傳送門,但是其實dp狀態只需要設計一個就行了,這是因為當我們使用傳送門的時候,總是在當前點建立傳送門,所以只

也就是隻要維護另一個傳送門即可

對於轉移,我們首先要把任務拆分掉,因為雖然一個任務有兩個位置,但是我們發現其實每一步可以看成一個任務,因為假如我在上一個任務的終點

對於當前任務a,b兩個位置,我要先以最小的走到a,再以最小的走到b,這是不衝突的,因此我們把每個走動的位置當作一個任務

剩下的就是選擇怎麼走,要不就是硬走,要不就是選擇傳送門走。另外我們還需要維護如果要新設定傳送門的狀態。

#include<bits/stdc++.h>
using namespace
std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=2e5+10; ll d[510][510]; int loc[N]; ll f[1000][510]; int main(){ ios::sync_with_stdio(false); int n,m,k; cin>>n>>m>>k; int i,j; for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ if(i==j) d[i][j]
=0; else{ d[i][j]=1e18; } } } for(i=1;i<=m;i++){ int a,b; ll c; cin>>a>>b>>c; d[a][b]=d[b][a]=min(d[a][b],c); } for(i=1;i<=k;i++){ int a,b; cin>>a>>b; loc[i
*2-1]=a; loc[i*2]=b; } for(int k=1;k<=n;k++){ for(i=1;i<=n;i++){ for(j=1;j<=n;j++) d[i][j]=min(d[i][j],d[i][k]+d[k][j]); } } for(i=0;i<=2*k;i++){ for(j=0;j<=n;j++){ f[i][j]=1e18; } } f[0][1]=0; loc[0]=1; for(i=0;i<2*k;i++){ for(j=1;j<=n;j++){ f[i+1][j]=min(f[i+1][j],f[i][j]+min(d[loc[i]][loc[i+1]],d[j][loc[i+1]])); for(int k=1;k<=n;k++){ f[i+1][k]=min(f[i+1][k],f[i][j]+min(d[loc[i]][k],d[j][k])+min(d[k][loc[i+1]],d[j][loc[i+1]])); } } } ll ans=1e18; for(i=1;i<=n;i++){ ans=min(ans,f[2*k][i]); } cout<<ans<<endl; }
View Code