难点:找出DP方程?
易错点:开long long
知识点:DP+任意一种最短路算法(Floyd都可以)
关于转移方程:
我们令DP[I]为第I天花费的最小“成本”
那么就有:
DP[i]=min{DP[j]+(i-j)*L+k}
0<j<i-1
我们可以这样理解,从第j天到第i天都采用当前(第i天)的最优方案
然后暴力更新即可?
一些易错点加在注释里面了
1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 #define int long long//主要因为懒 5 using namespace std; 6 inline int read(){ 7 char chr=getchar(); int f=1,ans=0; 8 while(!isdigit(chr)) {if(chr=='-') f=-1;chr=getchar();} 9 while(isdigit(chr)) {ans=(ans<<3)+(ans<<1);ans+=chr-'0';chr=getchar();} 10 return ans*f; 11 }void write(int x){ 12 if(x<0) putchar('-'),x=-x; 13 if(x>9) write(x/10); 14 putchar(x%10+'0'); 15 }const int M = 1005; queue<int> q; 16 int t,n,m,k,e,dp[M],head[M],ver[M],nxt[M],val[M],tm[101][M],vis[M],tot,dis[M],bk[M]; 17 inline void add(int x,int y,int z){ver[++tot]=y;nxt[tot]=head[x];val[tot]=z;head[x]=tot;} 18 int GET(){memset(dis,127,sizeof(dis));memset(bk,0,sizeof(bk));//关于SPFA,它死了,但这里的小数据显然卡不掉啊 19 while(!q.empty()) q.pop();q.push(1);dis[1]=0;bk[1]=1;//初始化 20 while(!q.empty()){ 21 int fx=q.front();q.pop();bk[fx]=0; 22 for(int i=head[fx];i;i=nxt[i]){ 23 int v=ver[i]; 24 if(vis[v]) continue;//在该时间访问非法节点 25 if(dis[v]>dis[fx]+val[i])//松弛 26 dis[v]=dis[fx]+val[i],(!bk[v])?(q.push(v),bk[v]=1):1; 27 } 28 }return dis[m]; 29 }signed main(){ 30 n=read(),m=read(),k=read(),e=read();memset(dp,127,sizeof(dp));dp[0]=0; 31 while(e--){int x=read(),y=read(),z=read();add(x,y,z),add(y,x,z);}//读入并建图 32 t=read();while(t--){int x=read(),y=read(),z=read();for(int i=y;i<=z;i++) tm[x][i]=1;}//读入并记录x号节点在y~z时间内是非法的 33 //-----------------读入和DP分割线(避免由于压行看不懂代码)------------------------------ 34 for(int i=1;i<=n;i++,memset(vis,0,sizeof(vis))) 35 for(int j=i-1;j>=0;j--){ 36 for(int k=1;k<=m;k++) if(tm[k][j+1]) vis[k]=1;//在这段时间内的非法节点 37 t=GET();if(t>=0x3f3f3f3f) break; 38 dp[i]=min(dp[i],dp[j]+(i-j)*t+k);//转移------ 39 }return write(dp[n]-k),0;//由于第一次更新路径时也当做修改操作,加上了k,在最后减掉即可 40 }