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

 dp状态的含义是,我完成当前任务i位于loc[i]处,传送门的位置在j

没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13381330.html