洛谷 P4009 汽车加油行驶问题 分层图 网络流 最小费用最大流 Dinic+Spfa 最短路

题目链接:

https://www.luogu.com.cn/problem/P4009

思路来源博客:

https://blog.csdn.net/qq_45458915/article/details/103630951

思路解释的非常清晰,建议再次查看

算法:1:分层图 网络流 最小费用最大流 Dinic+Spfa 最短路

图解:

1:选择一个n=3的单元来辅助理解思路

扫描二维码关注公众号,回复: 9950602 查看本文章

1:按剩余油量分为k+1层,图中蓝色的边为,原图中向右或者下,走一步,费用为0,天蓝色为,原图中向上或者向左走一步,费用为b,这两种边是从k层到1层向下一层连的,每一个点都有的,

2:绿色的边是有加油站的点才有的,是从0层到k-1层向,第k层连的边,费用为a,表示被强制加油,并且加满

3:红色的边,是新修建加油站,只有第0层,即油耗尽的那一层,原来没有加油站的点向第k层连边,表示修建并且油加满,费用为a+c

题目大意:给出一个n*n的矩阵表示道路,途中有一些加油站,现在要从点(1,1)到达点(n,n),问最小花费,其中的一些规则如下:

1:汽车只能沿着网格边行驶,装满油后可以行驶k条边,出发时已经装满油

2:汽车经过一条网格边时,若x或y减小,需要花费b元,其余情况没有花费

3:汽车在行驶过程中遇到油库则必须强制加满油,并花费a元

4:在需要时可以在网格点增设临时油库,并支付花费c元(不包括加油的a元)

5:n,k,a,b,c均为正整数,且满足2<=n<=100,2<=k<=10

思路:

1:关于建图,我们也可以直接建分层图,首先抛去油箱与加油站的情况,如果只是要求从起点到终点的最短路,那么我们直接在一层中进行连边,源点连向起点,流量为1,花费为0,然后按照上面的条件2连边,最后让终点连向汇点就好了

2:至于多出来的油箱限制,我们可以将每一种情况视为新的一层,我选择的是将k拆为k+1层图,每一层图代表当前油箱剩余的油还有多少,那么在转移的时候,符合条件的连边就可以直接从(i,j,k)连边到(x,y,k-1)了

3:对于每个油库,因为是强制满油,所以我们可以将该点[0,k-1]层的点都向第k层的点连边,花费为a,只有第k层才能向四周连边

4:而对于非油库的点,最优解肯定是当油箱空了的时候才建立临时油库,所以只需要让第0层的该点向第k层建边,花费为a+c就好了

建图描述:

三维点表示的是(x,y,k),x,y代表坐标,k代表层数

    1: 源点->(1,1,k),流量为1,花费为0
    2:(x,y,k)->(x,y,k-1),流量为无穷大,花费符合条件2
    3:当前点是否为油库:
            1:是油库:(x,y,t)t∈[0,k-1]->(x,y,k),流量为无穷大,花费为a
            2:不是油库:(x,y,0)->(x,y,k),流量为无穷大,花费为a+c
    4:(n,n,t)t∈[0,k]->汇点,流量为无穷大,花费为0

 

代码:

#include <bits/stdc++.h>
//不知道为什么,这样写,不可以,要写成下边的函数形式
//#define xuhao(i,j,k,n) ((i-1)*n+j+n*n*k)
#define hefa(x,di,top) (di<=x&&x<=top)

using namespace std;
const int maxn=1e5+1e4+2,maxm=1e6+2e4+2e1+5,inf=1<<31-1;
int n,k,s,t,a,b,c,tot=1,oil,head[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn],maxflow,mincost;
bool vis[maxn];
queue<int>q;
const int d[4][2]=
{
    {1,0},{-1,0},{0,1},{0,-1}
};

struct edge
{
    int to,next,w,dis;
}e[maxm];

int xuhao(int i,int j,int k,int n)
{
    return (i-1)*n+j+n*n*k;
}

void addedge(int x,int y,int w,int dis)
{
    e[++tot].to=y;e[tot].w=w;e[tot].dis=dis;e[tot].next=head[x];head[x]=tot;
    e[++tot].to=x;e[tot].w=0;e[tot].dis=-dis;e[tot].next=head[y];head[y]=tot;
}

bool spfa(int s,int t)
{
    memset(dis,0x7f,sizeof(dis));
    memset(flow,0x7f,sizeof(flow));
    memset(vis,0,sizeof(vis));
    q.push(s);vis[s]=1;dis[s]=0;pre[t]=-1;
    while(!q.empty())
    {
        int now=q.front();q.pop();
        vis[now]=0;
        for(int i=head[now];i;i=e[i].next)
        {
            int y=e[i].to;
            if(e[i].w>0&&dis[y]>dis[now]+e[i].dis)
            {
                dis[y]=dis[now]+e[i].dis;
                pre[y]=now;
                last[y]=i;
                flow[y]=min(flow[now],e[i].w);
                if(!vis[y])
                {
                    q.push(y);
                    vis[y]=1;
                }
            }
        }
    }
    return pre[t]!=-1;
}

void dfs()
{
    int now=t;
    maxflow+=flow[t];
    mincost+=flow[t]*dis[t];
    while(now!=s)
    {
        e[last[now]].w-=flow[t];
        e[last[now]^1].w+=flow[t];
        now=pre[now];
    }
}

int main()
{
    ios::sync_with_stdio(0);
    scanf("%d %d %d %d %d",&n,&k,&a,&b,&c);
    s=0,t=n*n*(k+1)+1;
    addedge(s,xuhao(1,1,k,n),1,0);
    for(int i=0;i<=k;i++)addedge(xuhao(n,n,i,n),t,inf,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&oil);
            if(oil)
            {
                for(int t=0;t<k;t++)addedge(xuhao(i,j,t,n),xuhao(i,j,k,n),inf,a);
                for(int t=0;t<4;t++)
                {
                    int x=i+d[t][0];
                    int y=j+d[t][1];
                    if(hefa(x,1,n)&&hefa(y,1,n))
                    {
                        int flag=0;
                        if(x<i||y<j)flag=b;
                        addedge(xuhao(i,j,k,n),xuhao(x,y,k-1,n),inf,flag);
                    }
                }
            }
            else
            {
                for(int t=0;t<4;t++)
                {
                    int x=i+d[t][0];
                    int y=j+d[t][1];
                    if(hefa(x,1,n)&&hefa(y,1,n))
                    {
                        int flag=0;
                        if(x<i||y<j)flag=b;
                        for(int p=1;p<=k;p++)addedge(xuhao(i,j,p,n),xuhao(x,y,p-1,n),inf,flag);
                    }
                }
                addedge(xuhao(i,j,0,n),xuhao(i,j,k,n),inf,a+c);
            }
        }
    while(spfa(s,t))dfs();
    printf("%d\n",mincost);
    return 0;
}


 

发布了164 篇原创文章 · 获赞 82 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/aiwo1376301646/article/details/104385325