[24 network flow problem] vehicle refueling problem (layered graph)

The meaning of problems

link

Thinking

Fake network flow

Since oil can not be stored directly in this state, together with a small k, the original image can be layered, k + 1 is divided into FIG layer, respectively, the current amount of oil is 0 ~ k

Even edge

  1. For the first full k layer of oil, even to the four directions, if you go right back to the value of B, 0 otherwise, represents one step away

  2. For non-filled reservoir, a gas station if the current point, then it is only a point to point k-th layer corresponds to the edge, the right value of A, represents between refueling

  3. For non-filled reservoir, if the current node is not a gas station, then it can be connected to the four directions corresponding to the next layer, the same one; it also has one side connected to the corresponding point of the k-th layer, a weight of A + C, represents and establishing between refueling stations (go up because each point on the grid of FIG once, so that even the sides of correctness can be guaranteed)

  4. Finally, the end point corresponding to the point k + 1 is connected to the meeting point t, the right side is 0

S from the starting point of the k-th layer, the shortest run, dis [t], is the answer

Code:

#include<bits/stdc++.h>
#define N 200005
#define M 2000005
using namespace std;
int n,k,A,B,C,s,t;
int a[105][105];
int dis[N];
bool vis[N];

struct Node
{
    int u,dis;
    bool operator < (const Node a)const
    {
        return a.dis<dis;
    }
};
struct Edge
{
    int next,to,dis;
}edge[M];int head[N],cnt;
void add_edge(int from,int to,int dis)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    edge[cnt].dis=dis;
    head[from]=cnt;
}
void dijkstra(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    priority_queue<Node> q;
    q.push((Node){s,0});
    dis[s]=0;
    while(!q.empty())
    {
        int u=q.top().u;q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].dis)
            {
                dis[v]=dis[u]+edge[i].dis;
                if(!vis[v]) q.push((Node){v,dis[v]});
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d",&n,&k,&A,&B,&C);
    s=1;t=N-5;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            scanf("%d",&a[i][j]);
        //代码中i=0为满油层
    for(int i=0;i<=k;++i)
        for(int j=1;j<=n;++j)
            for(int p=1;p<=n;++p)
            {
                int id=(j-1)*n+p,step=n*n;
                if(!a[j][p]||!i)//不是加油站,可以向四周连边;或者满油位置 
                {
                    if(i!=k)//还有油 
                    {
                        if(p!=n) add_edge(step*i+id,step*(i+1)+id+1,0);//向右
                        if(p!=1) add_edge(step*i+id,step*(i+1)+id-1,B);//向左
                        if(j!=n) add_edge(step*i+id,step*(i+1)+id+n,0);//向下
                        if(j!=1) add_edge(step*i+id,step*(i+1)+id-n,B);//向上
                    }
                }
                if(a[j][p]&&i) add_edge(step*i+id,id,A);//加油站
                if(!a[j][p]&&i) add_edge(step*i+id,id,A+C);//新建加油站 
            }
    for(int i=0;i<=k;++i) add_edge(n*n*(i+1),t,0);//连终点 
    dijkstra(s);
    cout<<dis[t]<<endl;
    return 0;
}

Guess you like

Origin www.cnblogs.com/Chtholly/p/11325010.html