题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1924
思路:
1.二分所需花费cost,每次只选择不大于cost的航班。
2.设源点S,汇点T。对于每个城市,表示为二元组(i,t),代表第t天处于第i个城市。从S到每一(i,0)连边,容量为每个城市人数;从(n,d)到T连边,容量为INF。
3.对于每个个航班,从城市i到城市j,出发时间为e,到达时间为e+1。连边(i,e)->(j,e+1),容量为航班限制人数。
4.由于可在城市停留,连边(i,e)->(i,e+1),容量为INF。
5.若最大流等于总人数,则当前花费可满足条件。
#include
#include
#include
#include
#include
#include
#include
#define debug
using namespace std;
const int maxn = 400 + 50;
const int maxm = 1000 + 50;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from, to, cap, flow;
Edge(int a, int b, int c, int d) :from(a), to(b), cap(c), flow(d) {}
};
struct Dinic
{
int n, m, s, t;
vector edges;
vector G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n)
{
this->n = 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 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;
}
};
struct Node
{
int u, v, c, p, e;
};
Dinic g;
int p[40];
Node a[maxm];
int id[40][15];
int n, d, m, maxx;
int cnt, S, T, sum;
int check(int x)
{
g.init(cnt + 1);
for (int i = 1; i <= n; i++)
{
g.addEdge(S, id[i][0], p[i]);
for (int j = 0; j <= d; j++)
{
g.addEdge(id[i][j], id[i][j + 1], INF);
}
}
g.addEdge(id[n][d], T, INF);
for (int i = 0; i < m; i++)
{
Node& tmp = a[i];
if (tmp.p <= x)
{
g.addEdge(id[tmp.u][tmp.e], id[tmp.v][tmp.e + 1], tmp.c);
}
}
return g.MaxFlow(S, T) == sum;
}
void init()
{
cnt = 0;
sum = 0;
maxx = -INF;
memset(id, 0, sizeof(id));
}
int main()
{
#ifdef debu
freopen("in.txt", "r", stdin);
#endif
int t, cas = 0;
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d", &n, &d, &m);
init();
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= d; j++)
{
id[i][j] = ++cnt;
}
}
for (int i = 0; i < m; i++)
{
int u, v, c, p, e;
scanf("%d%d%d%d%d", &u, &v, &c, &p, &e);
a[i] = Node{ u,v,c,p,e };
maxx = max(maxx, p);
}
S = 0, T = cnt + 1;
g.init(cnt + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &p[i]);
sum += p[i];
}
int l = 0, r = maxx, ans = -1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
{
r = mid - 1;
ans = mid;
}
else
{
l = mid + 1;
}
}
printf("Case #%d: ", ++cas);
if (ans == -1) printf("Impossible\n");
else printf("%d\n", ans);
}
return 0;
}