题目大意
给出一幅无向图(点数<=20),在n天内,有某些点在某段时间不能经过,求n天最短路之和,每相邻两天所走路不同将付出额外代价k,求最小代价。
题解
用单最短路算法求出任意一段时间用同样路径的花费。f[i]表示1到i天的花费,f[j]=min{f[i]+cost[i+1][j]*(j-i)+k}(j>i)。
#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=100,maxm=20;
int n,m,k,e,d,dis[maxm+10],queue[maxm*5+10],map[maxm+10][maxm+10],unable[maxm+10][maxn+10],
cost[maxn+10][maxn+10],f[maxn+10];
bool inqueue[maxm+10];
int spfa(int u,int v){
memset(dis,63,sizeof(dis));
dis[1]=0;int head=0,tail=0;
inqueue[queue[++tail]=1]=1;
while(head!=tail){
int now=queue[++head];
inqueue[now]=0;
fo(i,1,m)
if(map[now][i]&&(dis[now]+map[now][i]<dis[i])&&(unable[i][v]-unable[i][u-1]==0)){
dis[i]=dis[now]+map[now][i];
if(!inqueue[i])inqueue[queue[++tail]=i]=1;
}
}
return dis[m];
}
int main(){
scanf("%d%d%d%d",&n,&m,&k,&e);
memset(map,63,sizeof(map));
fo(i,1,e){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
map[u][v]=map[v][u]=min(map[u][v],w);
}
scanf("%d",&d);
fo(i,1,d){
int p,a,b;scanf("%d%d%d",&p,&a,&b);
fo(j,a,b)unable[p][j]=1;
}
fo(i,1,m)
fo(j,1,n)unable[i][j]+=unable[i][j-1];
fo(i,1,n)
fo(j,i,n)
cost[i][j]=spfa(i,j);
memset(f,63,sizeof(f));f[0]=-k;int inf=f[1];
fo(i,1,n)
fo(j,0,i-1)
if((f[j]!=inf)&&(cost[j+1][i]!=inf))f[i]=min(f[i],f[j]+cost[j+1][i]*(i-j)+k);
printf("%d",f[n]);
}