LUOGU 4452 [国家集训队]航班安排 最大费用最大流

版权声明:转载注明即可。。 https://blog.csdn.net/huashuimu2003/article/details/91435334

title

LUOGU 4452
题目描述

神犇航空有 K K 架飞机,为了简化问题,我们认为每架飞机都是相同的。神犇航空的世界中有 N N 个机场,以 0 N 1 0\cdots N-1 编号,其中 0 0 号为基地机场,每天0时刻起飞机才可以从该机场起飞,并不晚于 T T 时刻回到该机场。一天,神犇航空接到了 M M 个包机请求,每个请求为在 s s 时刻从 a a 机场起飞,在恰好 t t 时刻到达 b b 机场,可以净获利 c c 。设计一种方案,使得总收益最大。

输入输出格式
输入格式:

第一行,4个正整数 N , M , K , T N,M,K,T ,如题目描述中所述;
以下 N N 行,每行 N N 个整数,描述一个 N N N∗N 的矩阵 t t t ­ i j t­_{ij} 表示从机场 i i 空载飞至机场 j j ,需要时间 t i j t_{ij}
以下 N N 行,每行 N N 个整数,描述一个 N N N∗N 的矩阵 f f f ­ i j f_{­ij} 表示从机场 i i 空载飞至机场 j j ,需要费用 f i j f_{ij}
以下 M M 行,每行5个整数描述一个请求,依次为 a , b , s , t , c a,b,s,t,c

输出格式:

仅一行,一个整数,表示最大收益。

输入输出样例
输入样例#1:

2 1 1 10
0 5
5 0
0 5
5 0
0 1 0 5 10

输出样例#1:

5

说明

对于10%的测试数据, K = 1 K=1
另有20%的测试数据, K = 2 K=2
对于全部的测试数据, N , M < = 200 K < = 10 T < = 3000 t i j < = 200 f i j < = 2000 0 < = a , b < N 0 < = s < = t < = T 0 < = c < = 10000 t i i = f i i = 0 t i j < = t i k + t k j f i j < = f i k + f k j N,M<=200,K<=10,T<=3000,t_{ij}<=200,f_{ij}<=2000,0<=a,b<N,0<=s<=t<=T,0<=c<=10000,t_{ii}=f_{ii}=0,t_{ij}<=t_{ik}+t_{kj},f_{ij}<=f_{ik}+f_{kj}

analysis

说一下做法:

  1. 考虑以请求为点进行建图,对每个请求进行拆点,拆点后两个点之间连容量为 1 1 ,代价为 c c 的边,代表着一个请求只能执行一次。

  2. 考虑时间限制:
    <1>. 对于一个请求,如果 0 0 时刻可以从 0 0 机场飞到该请求的起点机场,那么 s 源点s 向该请求连容量为 I N F INF ,代价为 ( ) (−飞行费用) 的边,代表花掉了这么多费用。
    <2>. 同理,若一个请求的结束时间,加上它的结束机场飞回 0 0 的时间小于等于总的时间限制, 该请求 t 汇点t 连边。
    <3>. 但是每次执行完一个请求并未规定一定要飞回 0 0 机场,也可以飞去其他请求的起点机场,所以两两枚举请求,如果满足时间条件也进行连边。

  3. 考虑有 k k 架飞机:再建一个 s 源点s&#x27; ,向 s 源点s 连容量为 k k ,代价为 0 0 的边即可。

  4. 跑最大费用最大流即可。

当然我们肯定是要思考一下为什么可以这么做。

我刚看到这道题的时候,因为是奔着网络流题目才写的,所以当看到题目要求求出最大收益时,便不假思索的想到要用最大费用最大流。当然,这也是经过训练后才能产生的“直觉”。

然后,这道题其实蕴含了“飞机模型”、“费用流模型”(即我刚刚所说的最大收益),这才让我们能想到网络流之类的算法。

当然,我的语言可能有混乱(望路过大佬给出建议),但是,只是想传达思考是很重要的,读题是很重要的(除了题目描述不清的破题)。

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010,maxm=1e6,inf=0xcfcfcfcf,INF=0x3f3f3f3f;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}

template<typename T>inline void write(T x)
{
	if (!x) { putchar('0'); return ; }
	if (x<0) putchar('-'), x=-x;
	T num=0, ch[20];
	while (x) ch[++num]=x%10+48,x/=10;
	while (num) putchar(ch[num--]);
}

int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],cost[maxm<<1],head[maxn],len=1;
inline void add(int x,int y,int z,int c)
{
	ver[++len]=y,edge[len]=z,cost[len]=c,Next[len]=head[x],head[x]=len;
	ver[++len]=x,edge[len]=0,cost[len]=-c,Next[len]=head[y],head[y]=len;
}

int S,T;
int dist[maxn],incf[maxn],pre[maxn];
bool vis[maxn];
inline bool spfa()
{
	memset(dist,0xcf,sizeof(dist));
	memset(vis,0,sizeof(vis));
	queue<int>q;q.push(S);
	dist[S]=0,vis[S]=1,incf[S]=1<<30;
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		for (int i=head[x]; i; i=Next[i])
		{
			if (!edge[i]) continue;
			int y=ver[i];
			if (dist[y]<dist[x]+cost[i])
			{
				dist[y]=dist[x]+cost[i];
				incf[y]=min(incf[x],edge[i]);
				pre[y]=i;
				if (!vis[y]) q.push(y),vis[y]=1;
			}
		}
	}
	if (dist[T]==inf) return false;
	else return true;
}

long long maxflow,ans;
inline void update()
{
	int x=T;
	while (x!=S)
	{
		int i=pre[x];
		edge[i]-=incf[T];
		edge[i^1]+=incf[T];
		x=ver[i^1];
	}
	maxflow+=incf[T];
	ans+=dist[T]*incf[T];
}

int t[maxn][maxn],f[maxn][maxn];
int a[maxn],b[maxn],st[maxn],ed[maxn],c[maxn];
int main()
{
	int n,m,k,tim;
	read(n);read(m);read(k);read(tim);
	for (int i=0; i<n; ++i)
		for (int j=0; j<n; ++j) read(t[i][j]);
	for (int i=0; i<n; ++i)
		for (int j=0; j<n; ++j) read(f[i][j]);
	for (int i=1; i<=m; ++i)
		read(a[i]),read(b[i]),read(st[i]),read(ed[i]),read(c[i]);

	S=0,T=(n<<1)+2;
	for (int i=1; i<=m; ++i)
	{
		add(i<<1,i<<1|1,1,c[i]);
		for (int j=1; j<=m; ++j)
			if (ed[i]+t[b[i]][a[j]]<=st[j]) add(i<<1|1,j<<1,INF,-f[b[i]][a[j]]);

		if (t[S][a[i]]<=st[i]) add(S+1,i<<1,INF,-f[S][a[i]]);
		if (t[b[i]][S]+ed[i]<=tim) add(i<<1|1,T,INF,-f[b[i]][S]);
	}
	add(S,1,k,0);
	while (spfa()) update();
	write(ans),puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/91435334
今日推荐