题意:给出n天,m个点,e条边,k是一个改变航线用的花费
然后给出e条边的信息,有u v w,分别为u到v的长度是w
然后给出T组输入
也是三个值,x,l,r表示x港口在l到r天都不能使用
每天都要从港口1运东西到港口m,问n天的最小花费(修改航道要花费k)
solve:
设f[i]为i天的最小花费
那么就有f[i]=min(f[i],f[j]+(i-j)*dij(j+1,i)+k)这样的递推式
用f[j]的加上j+1天到i天的最短路径 *天数 +k,枚举这些值找最小的就是i天的最小花费
不知道有没有人有疑问为什么每次都要加k,不会存在f[j]跟dij(j+1,i)的路线相同吗? 确实的确存在,那为什么要加k?因为如果存在这种情况,那么肯定是前面某个j已经算过了,那么后面更新的+k是不可能小于前面那个值的
所以任意时候加k对答案的最小值没有影响!!!
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <iostream> using namespace std; #define ll long long #define fi first #define se second #define re register #define pb push_back void read(int &a) { a=0; int d=1; char ch; while(ch=getchar(),ch>'9'||ch<'0') if(ch=='-') d=-1; a=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9') a=a*10+ch-'0'; a*=d; } void write(int x) { if(x<0) putchar(45),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } ll f[105]; int a[30][30],dis[105]; int n,m,k,e; bool cnt[30][105],vis[30],book[30]; struct note { int dis,pos; bool operator < (const note &x) const { return x.dis<dis; } }; ll solve(int l,int r) { memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[1]=0; priority_queue <note> q; q.push({0,1}); for(re int i=1;i<=m;i++) for(re int j=l;j<=r;j++) vis[i]|=cnt[i][j]; while(!q.empty()) { note p=q.top();q.pop(); if(vis[p.pos]) continue; vis[p.pos]=1; for(re int i=1;i<=m;i++) { if(vis[i]) continue; if(dis[i]>dis[p.pos]+a[p.pos][i]) { dis[i]=dis[p.pos]+a[p.pos][i]; if(!vis[i]) q.push({dis[i],i}); } } } return 1ll*(r-l+1)*dis[m]; } int main() { read(n),read(m),read(k),read(e); memset(a,0x3f,sizeof(a)); for(re int i=1;i<=e;i++) { int u,v,w; read(u),read(v),read(w); a[u][v]=min(a[u][v],w); a[v][u]=min(a[v][u],w); } int T;read(T); while(T--) { int x,l,r; read(x),read(l),read(r); for(re int i=l;i<=r;i++) cnt[x][i]=true; } for(re int i=1;i<=n;i++) { f[i]=solve(1,i); for(re int j=2;j<i;j++) f[i]=min(f[i],f[j]+solve(j+1,i)+k); } printf("%lld ",f[n]); return 0; }