题解
论读题的重要性……
已经不止一次因为读错题把傻逼题看成不可做题了……
题意实际上时说,我们制定的这条路线,在这期间内,只有有一天,某个结点不可通过,就不行,也即选择每个结点必须都是这段时间内都可以通过的。
天数只有一百,直接f[i][j]把第i-j天的最短路求出来,再dp一波即可。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cctype>
using namespace std;
typedef long long ll;
const int inf=2e9;
int head[22],to[555],nxt[555],w[555],tot,f[102][102];
int lim[102],n,m,K,E,cnt,D;
int exi[22],vis[22],dis[22];ll dp[102];
queue<int>Q;
inline int rd()
{
char ch=getchar();int x=0,f=1;
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
inline void lk(int u,int v,int cp)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=cp;}
inline int spfa(int l,int r)
{
int x,i,j,cur=0;
for(i=0;i<m;++i) vis[i]=0,dis[i]=inf,exi[i]=1;
for(i=l;i<=r;++i) cur|=lim[i];
for(i=0;i<m;++i) if((1<<i) & cur) exi[i]=0;
dis[0]=0;vis[0]=1;Q.push(0);
while(!Q.empty()){
x=Q.front();Q.pop();vis[x]=0;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(!exi[j]) continue;
if(dis[j]>dis[x]+w[i]){
dis[j]=dis[x]+w[i];
if(!vis[j]) vis[j]=1,Q.push(j);
}
}
}
return dis[m-1];
}
int main(){
int i,j,x,y,z;
n=rd();m=rd();K=rd();E=rd();
for(i=1;i<=E;++i){x=rd()-1;y=rd()-1;z=rd();lk(x,y,z);lk(y,x,z);}
D=rd();
while(D--){
z=rd()-1;x=rd();y=rd();
for(i=x;i<=y;++i) lim[i]|=(1<<z);
}
for(i=1;i<=n;++i)
for(j=i;j<=n;++j)
f[i][j]=spfa(i,j);
for(i=1;i<=n;++i){
dp[i]=1ll*f[1][i]*i;
for(j=1;j<i;++j)
dp[i]=min(dp[i],dp[j]+(ll)K+1ll*f[j+1][i]*(i-j));
}
printf("%lld\n",dp[n]);
return 0;
}