P4009 汽车加油行驶问题 题解
这题貌似是个网络流?分层图?广搜?但实际上是个最短路的板子。
第一次做这题感觉上是一个建图加跑 dijstra 的模板,然后就照着打了。
想到对于每一个点,与自己所有相距小于等于 \(k\) 的边进行建立一条花费为 \(w\) 的边,对于每一条 \((x1,y1) 到 (x2,y2)\) 的边的意义是从点 \((x1,y1)\) 满油出发,到点 \((x2,y2)\) 时进行加油的最小花费。
由于强制消费的存在,所以建边时得进行动态维护。
对每一个点利用深搜,向上下左右四个方向搜索与自己距离小于等于 \(k\) 的所有的点,当搜索到点 \((x,y)\) 对应的为 \(1\) 时,进行强制加油,即退出搜索。否则继续搜下去,并且维护费用最小值。
在搜索结束后,出来进行建边即可。
搜索进行最优性剪枝,防止数据全为 \(0\)。
复杂度约为 \(O(n^2 \times k^2)\)。
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N=105;
struct node
{
int to,data;
};
vector<node>a[N*N];
int t[N][N],n,k,ta,tb,tc,f[4][2]={{1,1},{-1,1},{1,-1},{-1,-1}},dis[N*N],vis[N*N],num[N*N];
struct node2
{
int name,data;
};
priority_queue<node2>q;
bool operator <(node2 fi,node2 se)
{
return fi.data>se.data;
}
void dijstra()
{
q.push({1,0});
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
while(!q.empty())
{
int x=q.top().name;
q.pop();
if(vis[x])continue;
vis[x]=1;
int len=a[x].size();
for(int i=0;i<len;i++)
{
if(dis[a[x][i].to]>dis[x]+a[x][i].data)
{
dis[a[x][i].to]=dis[x]+a[x][i].data;
q.push({a[x][i].to,dis[a[x][i].to]});
}
}
}
}
void dfs(int x,int y,int step,int w)
{
if(x<1||y<1||x>n||y>n||step<0)return;
if(num[(x-1)*n+y]<=w+(t[x][y]^1)*(tc+ta)+t[x][y]*ta)return;
num[(x-1)*n+y]=w+(t[x][y]^1)*(tc+ta)+t[x][y]*ta;
if(t[x][y]==1)return;
dfs(x-1,y,step-1,w+tb);
dfs(x,y-1,step-1,w+tb);
dfs(x+1,y,step-1,w);
dfs(x,y+1,step-1,w);
}
int main()
{
scanf("%d%d%d%d%d",&n,&k,&ta,&tb,&tc);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&t[i][j]);
for(int i=1;i<=n*n;i++)num[i]=1e9;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dfs(i-1,j,k,tb);
dfs(i,j-1,k,tb);
dfs(i+1,j,k,0);
dfs(i,j+1,k,0);
for(int l=1;l<=k;l++)
{
for(int p=0;p<=l;p++)
{
for(int opt=0;opt<4;opt++)
{
int xx=i+p*f[opt][0],yy=j+(l-p)*f[opt][1];
if(xx<1||xx>n||yy<1||yy>n||num[(xx-1)*n+yy]==1e9)continue;
a[(i-1)*n+j].push_back((node){(xx-1)*n+yy,num[(xx-1)*n+yy]});
num[(xx-1)*n+yy]=1e9;
}
}
}
num[(i-1)*n+j]=1e9;
}
}
dijstra();
printf("%d",dis[n*n]-ta-tc);
return 0;
}
同时我也自己打了个分层图,很简单,就不说了。
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N=105;
const int K=15;
struct node
{
int to,data;
};
int t[N][N],n,k,ta,tb,tc,f[4][2]={{0,1},{1,0},{0,-1},{-1,0}},dis[N][N][K],sq[N][N][K];
struct node2
{
int x,y,k;
};
queue<node2>q;
void spfa()
{
q.push((node2){1,1,k});
memset(dis,0x3f,sizeof(dis));
dis[1][1][k]=0;
sq[1][1][k]=1;
while(!q.empty())
{
int x=q.front().x,y=q.front().y,d=q.front().k;
sq[x][y][d]=0;
q.pop();
for(int i=0;i<4;i++)
{
int xx=x+f[i][0],yy=y+f[i][1],dt=d-1,w=0;
if(xx<1||xx>n||yy<1||yy>n)continue;
if(dt<0)dt=k-1,w=ta+(t[x][y]^1)*tc;
if(xx<x)w+=tb;
if(yy<y)w+=tb;
if(t[xx][yy])dt=k,w+=ta;
if(dis[x][y][d]+w<dis[xx][yy][dt])
{
dis[xx][yy][dt]=dis[x][y][d]+w;
if(!sq[xx][yy][dt])
{
q.push({xx,yy,dt});
sq[xx][yy][dt]=1;
}
}
}
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&k,&ta,&tb,&tc);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&t[i][j]);
spfa();
int ans=1e9;
for(int i=0;i<=k;i++)ans=min(ans,dis[n][n][i]);
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号