UVA 10983 - Buy one, get the rest free(网络流)

题目链接:点击打开链接

思路: 

由于买一个价钱为p的航班, 那么所有<=p的航班都有了, 所以, 随着钱数的增加, 我们可以利用的航班也在增加而不会减少。  所以我们可以从小到大枚举买哪个航班, 然后观察题目中的各种限制, 可以想到用网络流求解。

对于所有价格<=p的航班,我们可以用一个二元组来表示结点, 用(x, y)表示第x天第y个城市。 那么如果在x这天有一个航班从y飞往k,就从(x, y)向(x+1, k)连一条容量为c的边, 这里的流就是人数, 点(x, y)像(x+1, y)连一条容量为INF的边, 表示下一个状态是停在这个城市一天。 当满流时说明所有人都到了城市n

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
// & 0x7FFFFFFF
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 1111;
struct Edge {
  int from, to, cap, flow;
};
bool operator < (const Edge& a, const Edge& b) {
  return a.from < b.from || (a.from == b.from && a.to < b.to);
}
struct Dinic {
  int n, m, s, t;        // 结点数, 边数(包括反向弧), 源点编号, 汇点编号
  vector<Edge> edges;    // 边表, edges[e]和edges[e^1]互为反向弧
  vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
  bool vis[maxn];        // BFS使用
  int d[maxn];           // 从起点到i的距离
  int cur[maxn];         // 当前弧指针
void init(int n) {
    for(int i = 0; i < n; i++) G[i].clear();
    edges.clear();
}
void AddEdge(int from, int to, int cap) {
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    m = edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    vis[s] = 1;
    d[s] = 0;
    while(!Q.empty()) {
      int x = Q.front(); Q.pop();
      for(int i = 0; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i]];
        if(!vis[e.to] && e.cap > e.flow) {  //只考虑残量网络中的弧
          vis[e.to] = 1;
          d[e.to] = d[x] + 1;
          Q.push(e.to);
        }
      }
    }
    return vis[t];
}
int DFS(int x, int a) {
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int& i = cur[x]; i < G[x].size(); i++) {  //上次考虑的弧
      Edge& e = edges[G[x][i]];
      if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
        e.flow += f;
        edges[G[x][i]^1].flow -= f;
        flow += f;
        a -= f;
        if(a == 0) break;
      }
    }
    return flow;
}
int Maxflow(int s, int t) {
    this->s = s; this->t = t;
    int flow = 0;
    while(BFS()) {
      memset(cur, 0, sizeof(cur));
      flow += DFS(s, INF);
    }
    return flow;
  }
}g;
int T, n, m, u, v, c, tot, d, num[maxn], kase = 0;
struct node {
    int u, v, c, p, e;
    node(int u=0, int v=0, int c=0, int p=0, int e=0):u(u),v(v),c(c),p(p),e(e) {}
    bool operator < (const node& rhs) const {
        return p < rhs.p;
    }
}a[maxn];
int get_id(int day, int city) {
    return (day) * n + city;
}
bool solve(int P) {
    g.init((n+1) * (d+1) + 10);
    int sor = (n+1)*(d+1) + 1;
    int tor = get_id(d, n);
    for(int i = 1; i <= n; i++) {
        int id = get_id(0, i);
        g.AddEdge(sor, id, num[i]);

        for(int j = 0; j < d; j++) {
            int id1 = get_id(j, i);
            int id2 = get_id(j+1, i);;
            g.AddEdge(id1, id2, INF);
        }
    }
    for(int i = 1; i <= m; i++) {
        if(a[i].p <= P) {
            if(a[i].e >= d) continue;
            int id1 = get_id(a[i].e, a[i].u);
            int id2 = get_id(a[i].e+1, a[i].v);
            g.AddEdge(id1, id2, a[i].c);
        }
        else break;
    }
    int ans = g.Maxflow(sor, tor);
    if(ans == tot) return true;
    return false;
}
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d",&n,&d,&m);
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d%d%d", &a[i].u, &a[i].v, &a[i].c, &a[i].p, &a[i].e);
        }
        sort(a+1, a+m+1);
        tot = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &num[i]);
            tot += num[i];
        }
        int ans = INF;
        for(int i = 1; i <= m; i++) {
            if(solve(a[i].p)) {
                ans = a[i].p; break;
            }
        }
        printf("Case #%d: ", ++kase);
        if(ans == INF) printf("Impossible\n");
        else printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值