列表

详情


NC20161. [JSOI2008]BLUE MARY的旅行

描述

在一段时间之后,网络公司终于有了一定的知名度,也开始收到一些订单,其中最大的一宗来自B市。Blue Mary决定亲自去签下这份订单。为了节省旅行经费,他的某个金融顾问建议只购买U航空公司的机票。U航空公司的所有航班每天都只有一班,并且都是上午出发当天下午到达的,所以他们每人每天只能坐一班飞机。
经过调查,他们得到了U航空公司经营的所有航班的详细信息,这包括每一航班的出发地,目的地以及最多能买到的某一天出发的票数。(注意: 对于一个确定的航班,无论是哪一天,他们最多能买到的那一天出发的票数都是相同的。) Blue Mary注意到他们一定可以只乘坐U航空公司的航班就从A市到达B市,但是,由于每一航班能买到的票的数量的限制,他们所有人可能不能在同一天到达B市。所以现在Blue Mary需要你的帮助,设计一个旅行方案使得最后到达B市的人的到达时间最早。

输入描述

第一行包含3个正整数N,M和T。题目中会出现的所有城市分别编号为1,2,…,N,其中城市A编号一定为1,城市B编号一定为N. U公司一共有M条(单向)航班。而连Blue Mary在内,公司一共有T个人要从A市前往B市。
以下M行,每行包含3个正整数X,Y,Z, 表示U公司的每一条航班的出发地,目的地以及Blue Mary最多能够买到的这一航班某一天出发的票数。(即:无论是哪一天,Blue Mary最多只能买到Z张U航空公司的从城市X出发到城市Y的机票。)
输入保证从一个城市到另一个城市的单向航班最多只有一个。

输出描述

仅有一行,包含一个正整数,表示最后到达B市的人的最早到达时间。假设他们第一次乘飞机的那一天是第一天。

示例1

输入:

3 3 5
1 2 1
2 3 5
3 1 4

输出:

6

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 10ms, 内存消耗: 700K, 提交时间: 2022-09-25 10:54:22

#include <iostream>
#include <cstring>

using namespace std;

const int N = 10010, M = 200010, INF = 0x3f3f3f3f;

int n, m, t, S, T;
int h[N], e[M], f[M], ne[M], idx;
int q[N], d[N], cur[N];
int g[51][51];

void insert(int u, int v, int d) {
    e[idx] = v, ne[idx] = h[u], f[idx] = d, h[u] = idx++;
    e[idx] = u, ne[idx] = h[v], f[idx] = 0, h[v] = idx++;
}

bool bfs() {
    int hh = 0, tt = -1;
    memset(d, -1, sizeof d);
    q[++tt] = S;
    d[S] = 0;
    cur[S] = h[S];
    while (hh <= tt) {
        int t = q[hh++];
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if (d[j] == -1 && f[i]) {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if (j == T) return true;
                q[++tt] = j;
            }
        }
    }
    return false;
}

int find(int u, int limit) {
    if (u == T) return limit;
    int flow = 0;
    for (int i = cur[u]; ~i && flow < limit; i = ne[i]) {
        cur[u] = i;
        int j = e[i];
        if (d[j] == d[u] + 1 && f[i]) {
            int t = find(j, min(f[i], limit - flow));
            if (!t) d[j] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic() {
    int r = 0, flow;
    while (bfs()) while (flow = find(S, INF)) r += flow;
    return r;
}

int get(int x, int day) {
    return (day - 1) * n + x;
}

int main() {
    cin >> n >> m >> t;
    while (m--) {
        int x, y, z;
        cin >> x >> y >> z;
        g[x][y] = z;
    }
    S = N - 1, T = S - 1;
    memset(h, -1, sizeof h);
    insert(S, get(1, 1), t);
    int res = 0;
    insert(get(n, 1), T, t);
    for (int day = 2; ; day++) {
        for (int i = 1; i <= n; i++) {
            insert(get(i, day - 1), get(i, day), t);
            for (int j = 1; j <= n; j++) {
                if (!g[i][j]) continue;
                insert(get(i, day - 1), get(j, day), g[i][j]);
            }
        }
        insert(get(n, day), T, t);
        res += dinic();
        if (res == t) {
            cout << day - 1;
            return 0;
        }
    }
    return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 10ms, 内存消耗: 968K, 提交时间: 2023-05-01 20:36:53

#include <bits/stdc++.h>
#define N 20100
#define M 245010
#define inf 0x7f7f7f7f
using namespace std;
/*
理论复杂度 N^2*M 增加了弧优化
*/
struct edg{
	int t,next,w;
}edge[10*M];
int n,m,s,t,T,ans,x,y,z,e[N][3];
int d[N],q[N]; // d[i]是层数,q是手工栈 
int head[N],cur[N],hcnt=-1;
void addedge(int x,int y,int w){
	edge[++hcnt].t=y;
	edge[hcnt].w=w;
	edge[hcnt].next=head[x];
	head[x]=hcnt;
}
bool makelevel(int s,int t){
	memset(d,0,sizeof(d));
	memset(q,0,sizeof(q));
	memcpy(cur,head,sizeof(head));
	d[s]=1;
	int l=0,r=0;
	q[r++]=s;
	while(l<r){
		int x=q[l++];
		if(x==t) return true;
		for(int i=head[x];i!=-1;i=edge[i].next){
			if(d[edge[i].t]==0 && edge[i].w!=0){
				q[r++]=edge[i].t;
				d[edge[i].t]=d[x]+1;
			}
		}
	} 
	return false;
}
int dfs(int x,int flow,int t){
	if(x==t) return flow;
	int sum=0;
	for(int i=cur[x];i!=-1;i=edge[i].next){
		cur[x]=i; // 网络流弧优化 
		if(edge[i].w!=0 && d[edge[i].t]==d[x]+1){
			int tmp=dfs(edge[i].t,min(edge[i].w,flow-sum),t);
			edge[i].w-=tmp;
			edge[i^1].w+=tmp;
			sum+=tmp;
			if(sum==flow) return sum;
		}
	}
	return sum;
}
int main(){
	memset(head,-1,sizeof(head));
	scanf("%d%d%d",&n,&m,&T);
	s=1;t=0;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
	}
	int tmp=0,ans;
	for(ans=1;;ans++){
		for(int i=1;i<=n;i++){
			addedge(i+(ans-1)*n,i+ans*n,inf);
			addedge(i+ans*n,i+(ans-1)*n,0);
		}
		for(int i=1;i<=m;i++){
			addedge(e[i][0]+(ans-1)*n,e[i][1]+ans*n,e[i][2]);
			addedge(e[i][1]+ans*n,e[i][0]+(ans-1)*n,0);
		}
		addedge(n+ans*n,t,inf);
		addedge(t,n+ans*n,0);
		while(makelevel(s,t)){
			tmp+=dfs(s,inf,t);
		}	
		//printf("%d %d\n",ans,tmp);
		if(tmp>=T) break;
	}
	printf("%d\n",ans);
	return 0;
} 

上一题