


转移方程:
- dis[i][j]:时间i~j不改变线路的最短路.
- cost[i]:从第1天到第i天的最低代价.
- cost[i]=cost[j]+dis(j+1,i)*(i-j)+k(0<=j<i).
初始值:
- cost[0]=-k.
基本思路:
- 预处理dis[i][j],进行cost[]转移即可.
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN=40,MAXM=8e2,MAXTIME=2e2;
struct Edge{
int from,to,w,nxt;
}e[MAXM];
int head[MAXN],edgeCnt=1;
void addEdge(int u,int v,int w){
e[++edgeCnt].from=u;
e[edgeCnt].to=v;
e[edgeCnt].w=w;
e[edgeCnt].nxt=head[u];
head[u]=edgeCnt;
}
struct Node{
int v,dis;
bool operator <(Node another)const{
return dis>another.dis;
}
};
int m;
int dis_dijktra[MAXN];
bool canGo[MAXN];
void dijkstra(){
memset(dis_dijktra,0x3f,sizeof(dis_dijktra));
priority_queue<Node> q;
if(canGo[1])q.push(Node{1,0});
dis_dijktra[1]=0;
while(!q.empty()){
Node nowNode=q.top();
q.pop();
int nowU=nowNode.v;
if(dis_dijktra[nowU]!=nowNode.dis)continue;
for(int i=head[nowU];i;i=e[i].nxt){
int nowV=e[i].to;
if(!canGo[nowV])continue;
if(dis_dijktra[nowV]>dis_dijktra[nowU]+e[i].w){
dis_dijktra[nowV]=dis_dijktra[nowU]+e[i].w;
q.push(Node{nowV,dis_dijktra[nowV]});
}
}
}
}
bool timeCanGo[MAXTIME][MAXN];
int getDis(int l,int r){//时间l到r的距离
memset(canGo,1,sizeof(canGo));
for(int i=1;i<=m;i++){
for(int j=l;j<=r;j++){
if(!timeCanGo[j][i])canGo[i]=0;
}
}
dijkstra();
return dis_dijktra[m];
}
ll dis[MAXTIME][MAXTIME];
int n,k;
ll cost[MAXTIME];
int main(){
int e;
scanf("%d%d%d%d",&n,&m,&k,&e);
for(int i=1;i<=e;i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
addEdge(a,b,w);
addEdge(b,a,w);
}
int d;
scanf("%d",&d);
memset(timeCanGo,1,sizeof(timeCanGo));
for(int i=1;i<=d;i++){
int p,a,b;
scanf("%d%d%d",&p,&a,&b);
for(int j=a;j<=b;j++){
timeCanGo[j][p]=0;
}
}
for(int l=1;l<=n;l++){
for(int r=1;r<=n;r++){
dis[l][r]=getDis(l,r);
}
}
memset(cost,0x3f,sizeof(cost));
cost[0]=-k;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
cost[i]=min(cost[i],cost[j]+dis[j+1][i]*(i-j)+k);
}
}
printf("%d\n",cost[n]);
return 0;
}