链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44569117");
}
题解:
首先我们跑出
fi,j
表示i到j这些天都是相同路线的最小代价。
然后暴力维护
gi
表示前i天最小代价。
fi,j
可以枚举
i,j
,暴力处理哪些点不能用,然后跑最短路。
时间复杂度
暴力处理废点
O(n3m)
SPFA 是
O(n2spfa)
大约
O(n2m2)?
反正能过。
然后暴力处理废点部分可以缩掉一个
n
降低时间复杂度上限。
就是类似利用单调性质哒。每次枚举
代码:
p、n、m、y:天数、点数、边数、改路代价。
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 110
#define M 1300
#define inf 0x3f3f3f3f
using namespace std;
struct Eli
{
int v,len,next;
}e[M];
int head[N],cnt;
inline void add(int u,int v,int len)
{
e[++cnt].v=v;
e[cnt].len=len;
e[cnt].next=head[u];
head[u]=cnt;
}
bool Dida[N],in[N];
int dist[N];
queue<int>q;
inline void spfa()
{
memset(dist,0x3f,sizeof dist);
int i,u,v;
q.push(1),dist[1]=0;
while(!q.empty())
{
u=q.front(),in[u]=0,q.pop();
for(i=head[u];i;i=e[i].next)
{
v=e[i].v;
if(Dida[v])continue;
if(dist[v]>dist[u]+e[i].len)
{
dist[v]=dist[u]+e[i].len;
if(!in[v])q.push(v),in[v]=1;
}
}
}
return ;
}
int n,m,p,y;
bool dida[N][N];
int f[N][N],g[N];
int main()
{
freopen("test.in","r",stdin);
int i,j,k;
int a,b,c;
scanf("%d%d%d%d",&p,&n,&y,&m);
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
for(i=b;i<=c;i++)dida[a][i]=1;
}
for(i=1;i<=p;i++)
{
memset(Dida,0,sizeof Dida);
for(j=i;j<=p;j++)
{
for(k=1;k<=n;k++)
Dida[k]|=dida[k][j];
spfa();
f[i][j]=dist[n];
}
}
for(i=1;i<=p;i++)g[i]=(f[1][i]<inf)?(f[1][i]*i):inf;
for(i=1;i<=p;i++)for(j=0;j<i;j++)if(f[j+1][i]<inf)
g[i]=min(g[i],g[j]+f[j+1][i]*(i-j)+y);
printf("%d\n",g[p]);
return 0;
}