思路:先把没有进行的场次规定双方都为负,对于x胜y负 变为x + 1胜 y - 1 负所需要的代价为 2 * C[ i ] * x - 2 * D[ i ] * y + C[ i ] + D[ i ],
我们根据这个拆边建图,对于a和b进行的一场w, w流出的流量为1,并指向a 和 b,然后跑费用流。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using namespace std; const int N = 6000 + 7; const int M = 2e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 +7; int n, m, win[N], lose[N], C[N], D[N], ans[N], cnt[N], S, T; int head[N], pre[N], dist[N], edgenum; bool vis[N]; PII a[N]; struct Edge { int from, to, cap, flow, cost, next; } edge[M]; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w, int c) { Edge E1 = {u, v, w, 0, c, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, -c, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } bool SPFA(int s, int t) { queue<int> Q; memset(dist, INF, sizeof(dist)); memset(vis, false, sizeof(vis)); memset(pre, -1, sizeof(pre)); dist[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow) { dist[E.to] = dist[u] + E.cost; pre[E.to] = i; if(!vis[E.to]) { vis[E.to] = true; Q.push(E.to); } } } } return pre[t] != -1; } void MCMF(int s, int t, LL &cost, int &flow) { flow = 0; cost = 0; while(SPFA(s, t)) { int Min = INF; for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) { Edge E = edge[i]; Min = min(Min, E.cap - E.flow); } for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) { edge[i].flow += Min; edge[i^1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } } int main() { init(); scanf("%d%d", &n, &m); S = 0, T = n + m + 1; for(int i = 1; i <= n; i++) { scanf("%d%d%d%d", &win[i], &lose[i], &C[i], &D[i]); cnt[i] = win[i] + lose[i]; } for(int i = 1; i <= m; i++) { scanf("%d%d", &a[i].fi, &a[i].se); addEdge(S, i, 1, 0); addEdge(i, m + a[i].fi, 1, 0); addEdge(i, m + a[i].se, 1, 0); cnt[a[i].fi]++; cnt[a[i].se]++; } LL ans = 0; for(int i = 1; i <= n; i++) { ans += 1ll * C[i] * win[i] * win[i] + 1ll * D[i] * (cnt[i] - win[i]) * (cnt[i] - win[i]); } for(int i = 1; i <= n; i++) { int num = cnt[i] - lose[i] - win[i]; int x = win[i], y = cnt[i] - win[i]; while(num--) { addEdge(m + i, T, 1, 2 * C[i] * x - 2 * D[i] * y + C[i] + D[i]); x++; y--; } } LL cost; int flow; MCMF(S, T, cost, flow); printf("%lld ", ans + cost); return 0; } /* */