题目链接:点击打开链接
题意:
给定n个点m条有向边的图, 起点s ,终点t
下面m条边 u,v, a,b 若选择这条边花费为a, 不选择花费为b
构造一条欧拉通路使得起点是s,终点是t,且花费最小。
思路:
首先能想到一个简单的思路:假设所有边都选择,然后在费用流里跑,就会出现负环的问题。。
所以为了避免负环,让所有费用都为正值:
int sum = 0;
若a>b, 则 费用要为正只能是 a-b, 默认这条边是删除是, sum += b, 那么如果我们要选择这条边,则从u=>v, 费用为a-b, 流量为1即可
若a<b, 则费用要为正只能是b-a, 默认这条边是选择是, sum += a, 那么如果我们要删除这条边,则相当于选一条反向的边,即v=>u,费用为b-a, 流量为1
因为我们要保持流量统一,所以用炒鸡汇源来维持,
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <iostream> template <class T> inline bool rd(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; while (c != '-' && (c<'0' || c>'9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } template <class T> inline void pt(T x) { if (x <0) { putchar('-'); x = -x; } if (x>9) pt(x / 10); putchar(x % 10 + '0'); } using namespace std; typedef int ll; #define inf 0x3f3f3f3f #define N 300 #define M 605*605*4 struct Edge { ll to, cap, cost, nex; Edge(){} Edge(ll to, ll cap, ll cost, ll next) :to(to), cap(cap), cost(cost), nex(next){} } edge[M << 1]; ll head[N], edgenum; ll D[N], A[N], P[N]; bool inq[N]; void add(ll from, ll to, ll cap, ll cost) { edge[edgenum] = Edge(to, cap, cost, head[from]); head[from] = edgenum++; edge[edgenum] = Edge(from, 0, -cost, head[to]); head[to] = edgenum++; } bool spfa(ll s, ll t, ll &flow, ll &cost) { for (ll i = 0; i <= t; i++) D[i] = inf; memset(inq, 0, sizeof inq); queue<ll>q; q.push(s); D[s] = 0; A[s] = inf; while (!q.empty()) { ll u = q.front(); q.pop(); inq[u] = 0; for (ll i = head[u]; ~i; i = edge[i].nex) { Edge &e = edge[i]; if (e.cap && D[e.to] > D[u] + e.cost) { D[e.to] = D[u] + e.cost; P[e.to] = i; A[e.to] = min(A[u], e.cap); if (!inq[e.to]) { inq[e.to] = 1; q.push(e.to); } } } } //若费用为inf则中止费用流 if (D[t] == inf) return false; cost += D[t] * A[t]; flow += A[t]; ll u = t; while (u != s) { edge[P[u]].cap -= A[t]; edge[P[u] ^ 1].cap += A[t]; u = edge[P[u] ^ 1].to; } return true; } ll flow, cost; ll Mincost(ll s, ll t){ flow = 0, cost = 0; while (spfa(s, t, flow, cost)); return cost; } void init(){ memset(head, -1, sizeof head); edgenum = 0; } int n, m, s, t, from, to; int in[N], out[N]; int main(){ int T, Cas = 1; rd(T); while (T--){ memset(in, 0, sizeof in); memset(out, 0, sizeof out); init(); rd(n); rd(m); rd(s); rd(t); from = 0, to = n + 1; ll now = 0; for (int i = 0, u, v, a, b; i < m; i++){ rd(u); rd(v); rd(a); rd(b); if (a > b){ now += b; add(u, v, 1, a - b); } else { now += a; add(v, u, 1, b - a); in[v]++; out[u]++; } } in[s]++; out[t]++; for (int i = 1; i <= n; i++){ if (in[i] > out[i]) add(from, i, in[i] - out[i], 0); else if (in[i] < out[i]) add(i, to, out[i] - in[i], 0); } Mincost(from, to); printf("Case %d: ", Cas++); for (int i = head[from]; ~i; i = edge[i].nex){ if (edge[i].cap)flow = -1; } if (flow == -1)puts("impossible"); else printf("%d\n", now + cost); } return 0; }
时间: 2024-10-01 04:08:42