title
LUOGU 4452
题目描述
神犇航空有 架飞机,为了简化问题,我们认为每架飞机都是相同的。神犇航空的世界中有 个机场,以 编号,其中 号为基地机场,每天0时刻起飞机才可以从该机场起飞,并不晚于 时刻回到该机场。一天,神犇航空接到了 个包机请求,每个请求为在 时刻从 机场起飞,在恰好 时刻到达 机场,可以净获利 。设计一种方案,使得总收益最大。
输入输出格式
输入格式:
第一行,4个正整数 ,如题目描述中所述;
以下 行,每行 个整数,描述一个 的矩阵 , 表示从机场 空载飞至机场 ,需要时间 ;
以下 行,每行 个整数,描述一个 的矩阵 , 表示从机场 空载飞至机场 ,需要费用 ;
以下 行,每行5个整数描述一个请求,依次为 。
输出格式:
仅一行,一个整数,表示最大收益。
输入输出样例
输入样例#1:
2 1 1 10
0 5
5 0
0 5
5 0
0 1 0 5 10
输出样例#1:
5
说明
对于10%的测试数据, ;
另有20%的测试数据, ;
对于全部的测试数据, 。
analysis
说一下做法:
-
考虑以请求为点进行建图,对每个请求进行拆点,拆点后两个点之间连容量为 ,代价为 的边,代表着一个请求只能执行一次。
-
考虑时间限制:
<1>. 对于一个请求,如果 时刻可以从 机场飞到该请求的起点机场,那么 向该请求连容量为 ,代价为 的边,代表花掉了这么多费用。
<2>. 同理,若一个请求的结束时间,加上它的结束机场飞回 的时间小于等于总的时间限制, 向 连边。
<3>. 但是每次执行完一个请求并未规定一定要飞回 机场,也可以飞去其他请求的起点机场,所以两两枚举请求,如果满足时间条件也进行连边。 -
考虑有 架飞机:再建一个 ,向 连容量为 ,代价为 的边即可。
-
跑最大费用最大流即可。
当然我们肯定是要思考一下为什么可以这么做。
我刚看到这道题的时候,因为是奔着网络流题目才写的,所以当看到题目要求求出最大收益时,便不假思索的想到要用最大费用最大流。当然,这也是经过训练后才能产生的“直觉”。
然后,这道题其实蕴含了“飞机模型”、“费用流模型”(即我刚刚所说的最大收益),这才让我们能想到网络流之类的算法。
当然,我的语言可能有混乱(望路过大佬给出建议),但是,只是想传达思考是很重要的,读题是很重要的(除了题目描述不清的破题)。
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;
}