题目大意:K架飞机,N个机场,以0..N-1编号,其中0号为基地机场,每天0时刻起飞机从该机场起飞,并不晚于T时刻回到该机场。M个包机请求,每个请求为在s时刻从a机场起飞,在恰好t时刻到达b机场,可以净获利c。机场之间来往有花费。求最大收益。
将每一个请求拆成两个点,在两个点之间连一条费用为负的完成请求x的利润,流量为1的边,表示完成请求获得了利润且只能完成一次。在0时刻可以选择完成任意一个请求x,若能不晚于请求x开始的时间到达请求x的起始点,则连一条从S到x,费用为从基地到x的起始点的花费,容量为INF的边;在完成一个请求后可以选择完成另一个请求或是直接返回基地,若能不晚于规定时间T回到基地,则连一条从x到T,费用为负的请求x的结束点到基地的费用,容量为INF的边;再判断请求之间的关系,若完成一个请求x后能从请求x的结束点在另一个请求y开始的时间之前到达请求y的起始点,就连一条从x到y,费用为从x的结束点到y的开始点的花费,容量为INF的边。
跑一边最小费用可行流后将费用取相反数即最大利润。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 505
#define INF 1000000000
using namespace std;
struct Edge {
int from,to,nxt,cap,cost;
}e[N*N];
struct Quest {
int a,b,s,t,c;
void scan() {scanf("%d%d%d%d%d",&a,&b,&s,&t,&c);}
}a[N];
int n,m,k,S,T,tim_lim,top=-1,t[N][N],c[N][N],fir[N];
void Add_Edge(int from,int to,int cap,int cost) {
e[++top].from=from;
e[top].to=to;
e[top].cap=cap;
e[top].cost=cost;
e[top].nxt=fir[from];
fir[from]=top;
e[++top].from=to;
e[top].to=from;
e[top].cap=0;
e[top].cost=-cost;
e[top].nxt=fir[to];
fir[to]=top;
return ;
}
bool SPFA(int& flow,int& cost) {
static bool inq[N];
static int f[N],d[N],p[N];
for(int i=S;i<=T;i++) d[i]=INF;
memset(inq,false,sizeof inq);
d[S]=0;
inq[S]=true;
p[S]=0;
f[S]=INF;
queue<int> q;
q.push(S);
while(!q.empty()) {
int x=q.front(); q.pop();
inq[x]=false;
for(int i=fir[x];~i;i=e[i].nxt) {
if(e[i].cap<1 || d[e[i].to]<=d[x]+e[i].cost) continue;
d[e[i].to]=d[x]+e[i].cost;
p[e[i].to]=i;
f[e[i].to]=min(f[x],e[i].cap);
if(!inq[e[i].to]) q.push(e[i].to), inq[e[i].to]=true;
}
}
if(d[T]>=0) return false;
flow+=f[T];
cost+=d[T]*f[T];
int x=T;
while(x!=S) {
e[p[x]].cap-=f[T];
e[p[x]^1].cap+=f[T];
x=e[p[x]].from;
}
return true;
}
int CostFlow() {
int flow=0,cost=0;
while(SPFA(flow,cost));
return cost;
}
int main() {
memset(fir,-1,sizeof fir);
scanf("%d%d%d%d",&n,&m,&k,&tim_lim);
S=0, T=m*2+2;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&t[i][j]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&c[i][j]);
for(int i=1;i<=m;i++) a[i].scan();
for(int i=1;i<=m;i++) {
Add_Edge(i*2,i*2+1,1,-a[i].c);
for(int j=1;j<=m;j++)
if(a[i].t+t[a[i].b][a[j].a]<=a[j].s)
Add_Edge(i*2+1,j*2,INF,c[a[i].b][a[j].a]);
if(t[0][a[i].a]<=a[i].s) Add_Edge(S+1,i*2,INF,c[0][a[i].a]);
if(a[i].t+t[a[i].b][0]<=tim_lim) Add_Edge(i*2+1,T,INF,c[a[i].b][0]);
}
Add_Edge(S,S+1,k,0);
printf("%d\n",-CostFlow());
return 0;
}