• 洛谷P4009 汽车加油行驶问题(分层最短路)


    传送门

    说好的网络流24题呢……上次是状压dp,这次怎么又最短路了……

    不过倒是用这题好好学了一下分层图最短路

    把每一个位置$(x,y)$,油量剩余$k$表示为一个状态,然后转化成一个$n$进制数,这样每一个状态都可以唯一表示。能互相转移的状态之间连有向边,然后跑一个最短路就行了

    具体细节看代码好了……细节太多说不清楚……

    ps:据说还可以用这个思想跑费用流,我估摸着大概是建源$S$和汇$T$,$S$向起点连,终点向$T$连,容量$inf$,费用$0$,然后各个状态之间的容量都是$1$,费用就是对应的转移的代价,跑个最小费用流就好了,因为用的也是spfa,似乎没啥区别(这整个ps都是这傻逼在口胡切勿当真)

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 using namespace std;
     6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     7 char buf[1<<21],*p1=buf,*p2=buf;
     8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
     9 inline int read(){
    10     #define num ch-'0'
    11     char ch;bool flag=0;int res;
    12     while(!isdigit(ch=getc()))
    13     (ch=='-')&&(flag=true);
    14     for(res=num;isdigit(ch=getc());res=res*10+num);
    15     (flag)&&(res=-res);
    16     #undef num
    17     return res;
    18 }
    19 const int N=350005,M=900005,inf=0x3f3f3f3f;
    20 int n,k,p,b,c,tot;
    21 bool vis[N],oil;
    22 int d[N],q[M];
    23 int head[N],Next[M],edge[M],ver[M];
    24 inline void add(int x1,int y1,int z1,int x2,int y2,int z2,int e){
    25     //可以理解成将这一个状态转化为一个n进制数 
    26     int u=n*n*(z1-1)+(x1-1)*n+y1,v=n*n*(z2-1)+(x2-1)*n+y2;
    27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
    28 }
    29 void spfa(){
    30     for(int i=1;i<=n*n*(k+1);++i) d[i]=inf;
    31     int h,t;q[h=t=1]=1,d[1]=0;
    32     while(h<=t){
    33         int u=q[h++];
    34         vis[u]=0;
    35         for(int i=head[u];i;i=Next[i]){
    36             int v=ver[i];
    37             if(d[v]>d[u]+edge[i]){
    38                 d[v]=d[u]+edge[i];
    39                 if(!vis[v]){
    40                     vis[v]=1,q[++t]=v;
    41                 }
    42             }
    43         }
    44     }
    45 }
    46 int main(){
    47     n=read(),k=read(),p=read(),b=read(),c=read();
    48     //k能走几条路,p加油费用,b逆行费用,c增设费用 
    49     for(int i=1;i<=n;++i){
    50         for(int j=1;j<=n;++j){
    51             oil=read();
    52             for(int l=1;l<=k;++l) add(i,j,l,i,j,l+1,0);
    53             if(oil){
    54                 //如果不满,强制加满
    55                 //然后要往边上走的话油就变为2了 
    56                 for(int l=2;l<=k+1;++l) add(i,j,l,i,j,1,p);
    57                 if(i<n) add(i,j,1,i+1,j,2,0);
    58                 if(j<n) add(i,j,1,i,j+1,2,0);
    59                 if(i>1) add(i,j,1,i-1,j,2,b);
    60                 if(j>1) add(i,j,1,i,j-1,2,b);
    61             }
    62             else{
    63                 for(int l=1;l<=k;++l){
    64                     if(i<n) add(i,j,l,i+1,j,l+1,0);
    65                     if(j<n) add(i,j,l,i,j+1,l+1,0);
    66                     if(i>1) add(i,j,l,i-1,j,l+1,b);
    67                     if(j>1) add(i,j,l,i,j-1,l+1,b);
    68                 }
    69                 //增设加油站 
    70                 for(int l=2;l<=k+1;++l) add(i,j,l,i,j,1,p+c);
    71             }
    72         }
    73     }
    74     spfa();
    75     int ans=inf;
    76     //终点的每一个状态:y+(x-1)*n+(k-1)*n*n
    77     //即n+(n-1)*n+(k-1)*n*n=n*n+(k-1)*n*n=k*n*n 
    78     for(int i=1;i<=k+1;++i) cmin(ans,d[n*n*i]);
    79     printf("%d
    ",ans);
    80     return 0;
    81 }
  • 相关阅读:
    poj 3252 Round Numbers 数位DP
    HDU5840 Problem This world need more Zhu 分块 树剖
    有向图强连通分量
    CodeForces
    Gym-100814K 数位DP 模拟除法
    洛谷P3455 [POI2007]ZAP-Queries
    洛谷P2257 YY的GCD
    洛谷P3327 [SDOI2015]约数个数和(莫比乌斯反演)
    莫比乌斯反演
    小知识点
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9498912.html
Copyright © 2020-2023  润新知