2018.10.21【网络流24题】【洛谷P4009】【LOJ6223】汽车加油行驶问题(最短路/费用流)

洛谷传送门

LOJ传送门


解析:

啊啊啊啊,这道题和网络流关系大吗?大吗?大吗?
就算是费用流来做实际上增广的过程也只被执行了一次,本质上仍然是最短路。

其实就是跑分层图的最短路,主要说说怎么构建分层图。

一看这个 k k k不好维护,它对路径的费用及贡献都十分的不可控,由于有一个强制消费机制的存在,我们根本没有办法令 k k k在状态中表示一个特定的东西。

那么我们令 d i s t [ ( i , j , k ) ] dist[(i,j,k)] dist[(i,j,k)]表示当前在 ( i , j ) (i,j) (i,j)这个位置,已经消耗的步数为 k k k的最小花费。

那么根据这个点是空地还是加油站都够非常方便的写出状态转移的式子了,按照式子建图跑最短路就好了。

费用流就是在最短路的基础上将源点的流量限制为1,边权改为费用,然后求最小费用。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=300005,M=1000006;
int last[N],nxt[M],to[M],ecnt;
int w[M];
inline void addedge(int u,int v,int val){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
}
int n,k,a,b,c;
#define pos(x,y,h) (n*n*(h-1)+n*(x-1)+y)

int dist[N];
bool vis[N];
set<pair<int,int> > q;
inline void dijkstra(){
	memset(dist,0x3f,sizeof dist);
	memset(vis,0,sizeof vis);
	dist[pos(1,1,1)]=0;
	q.insert(make_pair(0,pos(1,1,1)));
	while(!q.empty()){
		int u=q.begin()->second;
		q.erase(q.begin());
		if(vis[u])continue;
		vis[u]=true;
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
			if(dist[v]>dist[u]+w[e]){
				q.erase(make_pair(dist[v],v));
				dist[v]=dist[u]+w[e];
				q.insert(make_pair(dist[v],v));
			}
		}
	}
}

signed main(){
	n=getint();
	k=getint();
	a=getint();
	b=getint();
	c=getint();
	for(int re i=1;i<=n;++i){
		for(int re j=1;j<=n;++j){
			int f=getint();
			for(int re h=1;h<=k+1;++h){
				addedge(pos(i,j,h),pos(i,j,h+1),0);
			}
			if(f){
				addedge(pos(i,j,k+1),pos(i,j,1),a);
				if(i<n)addedge(pos(i,j,1),pos(i+1,j,2),0);
				if(j<n)addedge(pos(i,j,1),pos(i,j+1,2),0);
				if(i>1)addedge(pos(i,j,1),pos(i-1,j,2),b);
				if(j>1)addedge(pos(i,j,1),pos(i,j-1,2),b);
			}
			else{
				for(int re h=1;h<=k;++h){
					if(i<n)addedge(pos(i,j,h),pos(i+1,j,h+1),0);
					if(j<n)addedge(pos(i,j,h),pos(i,j+1,h+1),0);
					if(i>1)addedge(pos(i,j,h),pos(i-1,j,h+1),b);
					if(j>1)addedge(pos(i,j,h),pos(i,j-1,h+1),b);
				}
				for(int re h=2;h<=k+1;++h)addedge(pos(i,j,h),pos(i,j,1),a+c);
			}
		}
	}
	dijkstra();
	int ans=0x3f3f3f3f;
	for(int re i=1;i<=k+1;++i)ans=min(ans,dist[pos(n,n,i)]);
	cout<<ans;
	return 0;
}
Problem D:汽车最少费用加油行驶 Description 给定一个 N*N 的方形网格, 设其左上角坐标为 (1, 1), X 轴向右为正, Y 轴向下为正, 每个方格边长为 1, 右下角坐标为 (N, N). 一辆已装满油的汽车从 (1, 1) 为起点出发驶向终点 (N, N). 在若干个网格交叉点处设有油库供汽车行驶途中加油, 在起点与终点处不设油库. 汽车行驶过程中遵守如下规则: 1. 只能沿网格边行驶, 装满油后能行驶 K 条网格边 2. 当行驶经过一条网格边时, 若其 X 坐标或 Y 坐标减小, 则应付费用 B, 否则免付费用 3. 在行驶过程中遇油库则应加满油并付加油费用 A 4. 在需要时可在网格点处增设油库, 并付增设油库费用 C (不含加油费用A) 上述各数中的 N, K, A, B, C 均为正整数. 求汽车从起点出发到达终点的一条所付费用最少的行驶路线所需要的费用. Input 输入数据的第一行是 N, K, A, B, C 的值, 2 ≤ N ≤ 100, 2 ≤ K ≤ 10. 第二行起是一个 N*N 的 0-1 方阵, 每行 N 个值, 至 N+1 行结束. 方阵的第 i 行第 j 列处的值为 1 表示在网格交叉点 (i, j) 处设置有一个油库, 为 0 时表示未设有油库. 各行相邻的两个数以空格分隔. Output 对于测试用例的输入数据, 在一行上输出最优行驶路线所需的费用, 即最小费用. Sample Input 9 3 2 3 6 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 Sample Output 12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值