题意
给出一个m个的无向图,你需要规划n天的运输方案。n天里,每天都要从S走到T走一次,每个点在某些天里不能经过。每天需要花费等于路径长度的代价,而且如果第i天选择的路径与第i-1天不同(i>1),还需要多花K的修改路线代价。求最小总代价。
(n<=100,m<=20)
题解
脑洞题,不算太难。可能一开始会想的比较远,如果考虑路径的变化,发现难以下手。
实际上是个简单的线性DP。设f[i]表示前i天花费的总代价
转移方程:f[i]=min{f[j]+w(j+1,i)+K}
其中w(i,j)表示第i~j天都走同一条路的最短路径长,刷最短路即可。
可能会有疑问:f[i]这个状态并没有包含路径的信息啊,为什么不用判断w(j+1,i)走的路与f[j]是否相同呢?简单想一想就会发现这个不会影响到答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=405;
int n,m,w_c,e,f[maxn],dis[maxn],que[10005];
int fir[maxn],nxt[maxn],son[maxn],w[maxn],tot;
bool vis[maxn],ac[maxn][maxn],now[maxn];
bool add(int x,int y,int z){
son[++tot]=y; w[tot]=z; nxt[tot]=fir[x]; fir[x]=tot;
}
int spfa(){
if(!(now[1]&&now[m])) return -1;
memset(vis,0,sizeof(vis));
memset(dis,63,sizeof(dis)); int INF=dis[0];
int head=0,tail=1;
dis[1]=0; que[1]=1;
while(head!=tail){
int x=que[++head];
vis[x]=false;
for(int j=fir[x];j;j=nxt[j]) if(now[son[j]]&&dis[x]+w[j]<dis[son[j]]){
dis[son[j]]=dis[x]+w[j];
if(!vis[son[j]]) vis[son[j]]=true, que[++tail]=son[j];
}
}
return (dis[m]==INF)?-1:dis[m];
}
int main(){
scanf("%d%d%d%d",&n,&m,&w_c,&e);
for(int i=1;i<=e;i++){
int x,y,z; scanf("%d%d%d",&x,&y,&z);
add(x,y,z); add(y,x,z);
}
memset(ac,1,sizeof(ac));
int t; scanf("%d",&t);
while(t--){
int id,L,R; scanf("%d%d%d",&id,&L,&R);
for(int i=L;i<=R;i++) ac[id][i]=false;
}
memset(f,63,sizeof(f)); f[0]=-w_c;
for(int i=1;i<=n;i++){
memset(now,1,sizeof(now));
for(int j=i;j>=1;j--){
for(int k=1;k<=m;k++) if(!ac[k][j]) now[k]=false;
int res=spfa(); if(res==-1) break;
f[i]=min(f[i],f[j-1]+res*(i-j+1)+w_c);
}
}
printf("%d",f[n]);
return 0;
}