测试地址:物流运输
做法:本题需要用到DP+最短路。
容易想到,我们可以把这些天分成若干个区间,每个区间使用同一条运输路线,最优的运输路线当然就是不经过任何这几天中禁入的码头的最短路线,然后就是一个裸的区间型DP了,注意特判从一开始就使用同一条路线的情况即可。总的时间复杂度为
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf 2000000000
using namespace std;
int n,m,k,e,d,f[110],dis[25],g[25][25];
int forbid[110][25]={0},forb[25];
bool vis[25];
void dijkstra()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++) dis[i]=inf;
dis[1]=0;vis[1]=1;
for(int i=1;i<=m;i++)
if (g[1][i]!=-1&&!forb[i]) dis[i]=g[1][i];
for(int i=1;i<m;i++)
{
int v=-1,mn=inf;
for(int i=1;i<=m;i++)
if (!vis[i]&&dis[i]<mn) mn=dis[i],v=i;
if (v==-1) break;
vis[v]=1;
for(int i=1;i<=m;i++)
if (g[v][i]!=-1&&!forb[i]) dis[i]=min(dis[i],dis[v]+g[v][i]);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&e);
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
g[i][j]=-1;
for(int i=1;i<=e;i++)
{
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
if (g[a][b]==-1) g[a][b]=g[b][a]=d;
else g[a][b]=g[b][a]=min(g[a][b],d);
}
scanf("%d",&d);
for(int i=1;i<=d;i++)
{
int p,a,b;
scanf("%d%d%d",&p,&a,&b);
forbid[a][p]++,forbid[b+1][p]--;
}
for(int i=2;i<=n;i++)
for(int j=1;j<=m;j++)
forbid[i][j]+=forbid[i-1][j];
f[0]=0;
for(int i=1;i<=n;i++)
{
f[i]=inf;
for(int j=1;j<=m;j++) forb[j]=0;
for(int j=i;j>=2;j--)
{
for(int l=1;l<=m;l++)
forb[l]+=forbid[j][l];
dijkstra();
if (dis[m]==inf) break;
f[i]=min(f[i],f[j-1]+(i-j+1)*dis[m]+k);
}
if (dis[m]!=inf)
{
for(int j=1;j<=m;j++)
forb[j]+=forbid[1][j];
dijkstra();
if (dis[m]!=inf) f[i]=min(f[i],i*dis[m]);
}
}
printf("%d",f[n]);
return 0;
}