洛谷P4009汽车加油行驶问题——网络流24题(最短路)

题目:https://www.luogu.org/problemnew/show/P4009

网络流24题中不是网络流的最短路题;

把每个点拆成各个油量上的点,根据要求连边即可;

注意:点数最大为100*100*11,因为虽然k<=10,但还有k=0的状态!(竟然因为边界调了一晚上)

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
queue<int>q;
int const MAXN=110005,inf=1e9;//MAXN不可为100005 
int n,k,a,b,c,nd[15][105][105],cnt,ct=1,head[MAXN];
int dis[MAXN];
bool vis[MAXN];
struct N{
    int to,next,w;
    N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
}edge[MAXN*50];
void spfa()
{
    memset(dis,63,sizeof dis);
    int s=nd[k][1][1];
    dis[s]=0;vis[s]=1;q.push(s);
    while(q.size())
    {
        int x=q.front();q.pop();vis[x]=0;
//        cout<<x<<endl;
        for(int i=head[x];i;i=edge[i].next)
        {
            int u=edge[i].to;
            if(dis[u]>dis[x]+edge[i].w)
            {
//                cout<<dis[x]<<endl;
                dis[u]=dis[x]+edge[i].w;
                if(!vis[u])vis[u]=1,q.push(u);
            }
        }
//        cout<<q.size()<<endl;
    }
//    cout<<"spfa"<<endl;
//    ll mn=inf;
//    for(int l=0;l<=k;l++)
//        mn=min(mn,dis[nd[l][n][n]]);
    printf("%d",dis[cnt+1]);
}
int main()
{
    scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);//a加油 b返回 c建库 
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int l=0;l<=k;l++)
                nd[l][i][j]=++cnt;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            bool d;
            scanf("%d",&d);
            if(!d)
            {
                edge[++ct]=N(nd[k][i][j],head[nd[0][i][j]],a+c),head[nd[0][i][j]]=ct;
                for(int l=1;l<=k;l++)
                {
                    int x=nd[l][i][j];            
                    if(i>1)edge[++ct]=N(nd[l-1][i-1][j],head[x],b),head[x]=ct;
                    if(j>1)edge[++ct]=N(nd[l-1][i][j-1],head[x],b),head[x]=ct;
                    if(i<n)edge[++ct]=N(nd[l-1][i+1][j],head[x],0),head[x]=ct;
                    if(j<n)edge[++ct]=N(nd[l-1][i][j+1],head[x],0),head[x]=ct;
//                    if(l<k)edge[++ct]=N(nd[k][i][j],head[x],a+c),head[x]=ct;//不优! 
                }
            }
            if(d)
            {
                int x=nd[k][i][j];
                for(int l=0;l<k;l++)
                    edge[++ct]=N(x,head[nd[l][i][j]],a),head[nd[l][i][j]]=ct;
                if(i>1)edge[++ct]=N(nd[k-1][i-1][j],head[x],b),head[x]=ct;
                if(j>1)edge[++ct]=N(nd[k-1][i][j-1],head[x],b),head[x]=ct;
                if(i<n)edge[++ct]=N(nd[k-1][i+1][j],head[x],0),head[x]=ct;
                if(j<n)edge[++ct]=N(nd[k-1][i][j+1],head[x],0),head[x]=ct;
            }
        }
    for(int l=0;l<=k;l++)
        edge[++ct]=N(cnt+1,head[nd[l][n][n]],0),head[nd[l][n][n]]=ct;
//    cout<<cnt<<endl; 
    spfa();
    return 0;
}

 

posted @ 2018-04-12 00:05  Zinn  阅读(252)  评论(0编辑  收藏  举报