题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1003
DP好题;
直接找一个时间段的最短路,并用它来预处理出每个时间段的最小花费;
f[i]代表一条路走到时间的花费,所以转移要加上K。
枚举所有路线的TLE代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,K,e,head[25],ct,D,d[105],rt[405],pr[405],f[105][405],cnt,ans; bool vis[25]; struct N{ int to,next,w; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {} }edge[805]; void dfs(int x,int r,int p) { if(x==m) { rt[++cnt]=(r|(1<<(m-1))); pr[cnt]=p; return; } vis[x]=1; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].to; if(vis[v])continue; dfs(v,(r|(1<<(v-1))),p+edge[i].w); } vis[x]=0; } int main() { scanf("%d%d%d%d",&n,&m,&K,&e); for(int i=1,x,y,z;i<=e;i++) { scanf("%d%d%d",&x,&y,&z); edge[++ct]=N(y,head[x],z);head[x]=ct; edge[++ct]=N(x,head[y],z);head[y]=ct; } scanf("%d",&D); for(int i=1,p,a,b;i<=D;i++) { scanf("%d%d%d",&p,&a,&b); for(int j=a;j<=b;j++)d[j]|=(1<<(p-1));//第j天不能通过的码头 } dfs(1,1,0); memset(f,0x3f,sizeof f); for(int j=1;j<=cnt;j++)f[0][j]=0; for(int i=1;i<=n;i++) for(int j=1;j<=cnt;j++) { if(rt[j]&d[i])continue; for(int k=1;k<=cnt;k++) f[i][j]=min(f[i][j],f[i-1][k]+(j==k?pr[j]:K+pr[j])); } ans=0x3f; for(int j=1;j<=cnt;j++)ans=min(ans,f[n][j]); printf("%d",ans); return 0; }
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; queue<int>q; int const inf=0x3f3f3f3f; int n,m,K,e,head[25],ct,mr[105][105],D,zt[25],dis[25],f[105]; bool vis[25],d[25][105]; struct N{ int to,next,w; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {} }edge[805]; void spfa() { memset(vis,0,sizeof vis); memset(dis,0x3f,sizeof dis); while(q.size())q.pop(); dis[1]=0;q.push(1);vis[1]=1; while(q.size()) { int x=q.front();q.pop();vis[x]=0; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].to; if(dis[v]>dis[x]+edge[i].w&&!zt[v]) { dis[v]=dis[x]+edge[i].w; if(!vis[v])vis[v]=1,q.push(v); } } } } int main() { scanf("%d%d%d%d",&n,&m,&K,&e); for(int i=1,x,y,z;i<=e;i++) { scanf("%d%d%d",&x,&y,&z); edge[++ct]=N(y,head[x],z);head[x]=ct; edge[++ct]=N(x,head[y],z);head[y]=ct; } scanf("%d",&D); for(int i=1,p,a,b;i<=D;i++) { scanf("%d%d%d",&p,&a,&b); for(int j=a;j<=b;j++)d[p][j]=1; } for(int i=1;i<=n;i++) { memset(zt,0,sizeof zt); for(int j=i;j<=n;j++) { for(int k=1;k<=m;k++)zt[k]|=d[k][j]; spfa(); mr[i][j]=dis[m];//在下面乘 小心爆int } } for (int i=1;i<=n;i++) for (int j=i;j<=n;j++) if (mr[i][j]<inf)mr[i][j]*=(j-i+1); for(int i=1;i<=n;i++)f[i]=mr[1][i]; for(int i=2;i<=n;i++) { for(int j=1;j<i;j++) f[i]=min(f[i],f[j]+mr[j+1][i]+K); } printf("%d",f[n]); return 0; }