点击这里查看原题
c[i][j]表示i-j天走同一航线的最小花费,用SPFA处理。
于是得到方程:f[i]=min{f[j]+c[j+1][i]+k},最后结果为f[n]-k。
注意千万不要把n,m打反,我因为把最后结果打为f[m]-k,WA了3次
/*
User:Small
Language:C++
Problem No.:1003
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
int n,m,k,ee,f[105],c[105][105],fir[25],tot,d;
bool ban[25][105],vis[25];
struct edge{
int v,w,nex;
}e[10005];
void add(int u,int v,int w){
e[++tot]=(edge){v,w,fir[u]};
fir[u]=tot;
}
void spfa(int st,int ed){
bool un[25];
int dis[25];
memset(un,0,sizeof(un));
memset(dis,127,sizeof(dis));
for(int i=2;i<m;i++){
for(int j=st;j<=ed;j++){
if(ban[i][j]){
un[i]=1;
break;
}
}
}
queue<int> q;
q.push(1);
vis[1]=1;
dis[1]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=fir[u];i;i=e[i].nex){
int v=e[i].v;
if(un[v]) continue;
if(dis[u]+e[i].w<dis[v]){
dis[v]=dis[u]+e[i].w;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[m]<inf) c[st][ed]=dis[m]*(ed-st+1);
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d%d%d%d",&n,&m,&k,&ee);
while(ee--){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
scanf("%d",&d);
while(d--){
int p,a,b;
scanf("%d%d%d",&p,&a,&b);
for(int i=a;i<=b;i++) ban[p][i]=1;
}
memset(c,127,sizeof(c));
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
spfa(i,j);
for(int i=1;i<=n;i++){
f[i]=inf;
for(int j=0;j<i;j++)
if(c[j+1][i]<inf) f[i]=min(f[i],f[j]+c[j+1][i]+k);
}
printf("%d\n",f[n]-k);
return 0;
}