这道题是相当的火,但是在tyher的讲解下我一遍就AC了!!!
Part 1 理解题目
从第一天到最后一天,总会有一些点莫名其妙地走不了,所以导致我们不能按照上一次的最短路一直运输得到最少费用,而需要不停地更换航线来保证可以运到终点,答案就是在这些方案中选出运输费用最少的。
Part 2 思想过程
首先会想到我们每天都跑一遍SPFA,找最短路,如果和上一天不一样,那就改航线,加一下K的贪心方法。这样显然是错误的伪得不能再伪的贪心,而且要把最短路一个一个抠出来,不说T,写都写死你!
然后我们发现,这道题每天无非就两种决策,一种换航线,一种不换航线。那么,就可以想到dp(至于怎么想到的……题解帮我想的)我们设dp[i]表示前i天航行送完所有的货物所需要的最小花费。转移:dp[i]=min(dp[i],dp[j]+K+w[j+1][i]);这里的j是枚举的i之前的第几天,w[i][j]是从i天到j天航线都可以走的最短路,K是换航线的费用。既然出现了“最短路”这种东西,那就SPFA吧,把这期间不能走的点标记一下,跑一遍裸的SPFA,再记入数组,算一个王者预处理吧……哈哈哈……
Part 3 代码实现
dp过程
1 for(rg int i=1;i<=day;++i) 2 { 3 dp[i]=w[1][i]; 4 for(rg int j=1;j<i;++j) 5 { 6 p[i]=min(dp[i],dp[j]+K+w[j+1][i]); 7 } 8 }
SPFA之前的处理码头
读入损坏码头
1 for(rg int i=1;i<=d;++i) 2 { 3 rg int p=read(),a=read(),b=read(); 4 for(rg int j=a;j<=b;++j) 5 bre[j][++bre[j][0]]=p; 6 }
标记损坏码头(每一次枚举到的时间区间都要做)
memset(b,0,sizeof(b)); for(rg int k=i;k<=j;++k) { for(rg int l=1;l<=bre[k][0];l++) { b[bre[k][l]]=1; } }
SPFA模板
inline void SPFA() { memset(vis,0,sizeof(vis)); memset(team,0,sizeof(team)); for(rg int i=1;i<=n;++i)dis[i]=9999999; rg int top=0,tail=1; team[1]=1;vis[1]=1;dis[1]=0; while(top<tail) { top++; rg int now=team[top];vis[now]=0; for(rg int i=head[now];i;i=ljl[i].nxt) { rg int qw=ljl[i].to; if(dis[qw]>dis[now]+ljl[i].v&&!b[qw]) { dis[qw]=dis[now]+ljl[i].v; if(!vis[qw]) { team[++tail]=qw; vis[qw]=1; } } } } }
完整代码!!!
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #define rg register #define lst long long #define N 150 #define M 1200 using namespace std; int day,n,K,m,d,cnt; struct edge{ int to,v,nxt; }ljl[M<<1]; int head[N],team[N],dis[N],dp[N]; int w[N][N],bre[N][N]; bool vis[N],b[N]; inline int read() { rg int s=0,m=1;rg char ch=getchar(); while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar(); if(ch==‘-‘)m=-1,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)s=(s<<3)+(s<<1)+ch-‘0‘,ch=getchar(); return s*m; } inline void add(rg int p,rg int q,rg int o) { ljl[++cnt].to=q; ljl[cnt].v=o; ljl[cnt].nxt=head[p]; head[p]=cnt; } inline void SPFA() { memset(vis,0,sizeof(vis)); memset(team,0,sizeof(team)); for(rg int i=1;i<=n;++i)dis[i]=9999999; rg int top=0,tail=1; team[1]=1;vis[1]=1;dis[1]=0; while(top<tail) { top++; rg int now=team[top];vis[now]=0; for(rg int i=head[now];i;i=ljl[i].nxt) { rg int qw=ljl[i].to; if(dis[qw]>dis[now]+ljl[i].v&&!b[qw]) { dis[qw]=dis[now]+ljl[i].v; if(!vis[qw]) { team[++tail]=qw; vis[qw]=1; } } } } } int main() { day=read(),n=read(),K=read(),m=read(); for(rg int i=1;i<=m;++i) { rg int p=read(),q=read(),o=read(); add(p,q,o),add(q,p,o); } d=read(); for(rg int i=1;i<=d;++i) { rg int p=read(),a=read(),b=read(); for(rg int j=a;j<=b;++j) bre[j][++bre[j][0]]=p; } for(rg int i=1;i<=day;++i) { for(rg int j=i;j<=day;++j) { memset(b,0,sizeof(b)); for(rg int k=i;k<=j;++k) { for(rg int l=1;l<=bre[k][0];l++) { b[bre[k][l]]=1; } } SPFA(); if(dis[n]!=9999999)w[i][j]=(j-i+1)*dis[n]; else w[i][j]=dis[n]; } } for(rg int i=1;i<=day;++i) { dp[i]=w[1][i]; for(rg int j=1;j<i;++j) { dp[i]=min(dp[i],dp[j]+K+w[j+1][i]); } } cout<<dp[day]<<endl; return 0; }