[网络流24题] 汽车加油行驶问题

题目链接:戳我

分层图最短路问题。

我们设\(dp[i][k]\)表示节点为i,现在还有k条边可以走的状态。然后跑一个最短路就行了。因为是不定项更新,所以考虑spfa。

注意到了加油站是强制消费。然后分向上下左右四个方向走和原地建加油站五种情况来讨论。

注意最后更新答案的时候k==0不要忘了考虑!!(要不然就会像我一样WA掉一个点)

代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<algorithm>
#include<queue>
#define MAXN 100010
using namespace std;

int n,k,a,b,c,tot,edge_number,ans=2147483647;
int m[MAXN],dp[MAXN][20],id[210][210],done[MAXN][20],head[MAXN*110];
struct Node{int u,d;};
struct Edge{int nxt,to,dis;}edge[MAXN*110];

inline void add(int from,int to,int dis)
{
    edge[++edge_number].nxt=head[from];
    edge[edge_number].to=to;
    edge[edge_number].dis=dis;
    head[from]=edge_number;
}

inline void solve()
{
    queue<Node>q;
    memset(dp,0x3f,sizeof(dp));
    q.push((Node){id[1][1],k});
    dp[id[1][1]][k]=0;
    done[id[1][1]][k]=1;
    while(!q.empty())
    {
        int u=q.front().u,d=q.front().d;
        q.pop();done[u][d]=0;
        if(d!=0)
        {
            for(int i=head[u];i;i=edge[i].nxt)
            {
                int v=edge[i].to,yu=d-1,cur_dis=dp[u][d]+edge[i].dis;
                if(m[v]==1) yu=k,cur_dis+=a;
                if(cur_dis<dp[v][yu])
                {
                    dp[v][yu]=cur_dis;
                    if(!done[v][yu])
                        q.push((Node){v,yu}),done[v][yu]=1;
                }
            }
        }
        int cur_dis=dp[u][d]+c+a;
        if(m[u]==1) cur_dis-=c;
        if(cur_dis<dp[u][k])
        {
            dp[u][k]=cur_dis;
            if(!done[u][k])
                q.push((Node){u,k}),done[u][k]=1;
        }
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            id[i][j]=++tot,scanf("%d",&m[id[i][j]]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i!=1) add(id[i][j],id[i-1][j],b);
            if(j!=1) add(id[i][j],id[i][j-1],b);
            if(i!=n) add(id[i][j],id[i+1][j],0);
            if(j!=n) add(id[i][j],id[i][j+1],0);
        }
    }
    solve();
    for(int i=0;i<=k;i++) ans=min(ans,dp[id[n][n]][i]);
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-03-13 22:28  风浔凌  阅读(163)  评论(0编辑  收藏  举报