传送门:嘿原题在这
题意:给出一个图,求1~m的最短路,但其中有些点在某些时间段会不能用,题目保证有解。
我们可以很(不)容易的看出递推关系式dp[i]=min(dp[i],dp[j]+cost[j+1][i]+k)(0<=j<i)cost[i][j]表示从i到j这段时间的最短路。
//bzoj1003[ZJOI2006]物流运输
//by dadatu
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#define inf 0x3f3f3f3f
#define lim 1010
using namespace std;
queue<int> q;
int v[lim],head[lim],nextt[lim],c[lim],visit[lim],dist[lim],tag[lim],dp[lim],f[lim][lim],cost[lim][lim];
int n,m,e,k,d,tot=0;
void add_edge(int x,int y,int z){v[++tot]=y;c[tot]=z;nextt[tot]=head[x];head[x]=tot;}
void spfa()
{
memset(dist,inf,sizeof(dist));memset(visit,0,sizeof(visit));
q.push(1);visit[1]=1;dist[1]=0;
while(!q.empty())
{
int x=q.front();q.pop();visit[x]=0;
for (int i=head[x];i;i=nextt[i])
{
int y=v[i];
if (!tag[y]&&dist[y]>dist[x]+c[i])
{
dist[y]=dist[x]+c[i];
if (!visit[y]) q.push(y),visit[y]=1;
}
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&e);
for (int i=1;i<=e;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z);add_edge(y,x,z);
}
scanf("%d",&d);
for (int i=1;i<=d;i++)
{
int p,l,r;
scanf("%d%d%d",&p,&l,&r);
for (int j=l;j<=r;j++) f[p][j]=1;//记录一下l至r这段时间p码头被封
}
for (int i=1;i<=n;i++)
{
for (int j=i;j<=n;j++)
{
memset(tag,0,sizeof(tag));
for (int x=1;x<=m;x++)
for (int y=i;y<=j;y++) tag[x]|=f[x][y];//被封就打标记
spfa();
if (dist[m]<inf) cost[i][j]=dist[m]*(j-i+1);
else cost[i][j]=inf;//如果这种情况不存在cost也要赋值
}
}
memset(dp,inf,sizeof(dp));
dp[0]=-k;//如果一路不改路线就不用加上k了
for (int i=1;i<=n;i++)
for (int j=0;j<i;j++) dp[i]=min(dp[i],dp[j]+cost[j+1][i]+k);//递推式
printf("%d\n",dp[n]);
return 0;
}