先对0号节点做强连通,那么不在0号节点的强连通分量的点没有意义,可以舍弃掉。在0号节点的强连通分量里面的所有边都是至少走一次的,那么我们先统计答案,可以看出需要求的花的答案已经求出来了。原来强连通分量里面的边保留不变,流量设为无穷,费用为该边的费用,然后对连通分量所有点按度差建边,使全图入度和初度相同。。。跑出来的费用加上之前的费用就是最终答案。。。
#include <iostream> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <algorithm> #include <cstring> #include <climits> #include <cstdlib> #include <cmath> #include <time.h> #define maxn 305 #define maxm 20005 #define eps 1e-7 #define mod 1000000007 #define INF 0x3f3f3f3f #define PI (acos(-1.0)) #define lowbit(x) (x&(-x)) #define mp make_pair #define ls o<<1 #define rs o<<1 | 1 #define lson o<<1, L, mid #define rson o<<1 | 1, mid+1, R #define pii pair<int, int> #pragma comment(linker, "/STACK:16777216") typedef long long LL; typedef unsigned long long ULL; //typedef int LL; using namespace std; LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;} LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;} // head struct Edge { int v, c, w, next; Edge(int v = 0, int c = 0, int w = 0, int next = 0) : v(v), c(c), w(w), next(next) {} }E[maxm]; struct edge { int u, v, a, b, next; edge(int u = 0, int v = 0, int a = 0, int b = 0, int next = 0) : u(u), v(v), a(a), b(b), next(next) {} }EE[maxm]; int in[maxn]; int out[maxn]; int dfn[maxn]; int low[maxn]; stack<int> ss; queue<int> q; int H[maxn], cntE; int h[maxn], cntEE; int cap[maxn]; int dis[maxn]; int cur[maxn]; int vis[maxn]; int ins[maxn]; int scc[maxn]; int dfs_clock, n, m; int flow, cost, s, t, T; void add_edges(int u, int v, int a, int b) { EE[cntEE] = edge(u, v, a, b, h[u]); h[u] = cntEE++; } void addedges(int u, int v, int c, int w) { E[cntE] = Edge(v, c, w, H[u]); H[u] = cntE++; E[cntE] = Edge(u, 0, -w, H[v]); H[v] = cntE++; } void init() { cntEE = cntE = T = dfs_clock = 0; memset(h, -1, sizeof h); memset(H, -1, sizeof H); memset(in, 0, sizeof in); memset(out, 0, sizeof out); memset(scc, 0, sizeof scc); memset(ins, 0, sizeof ins); memset(vis, 0, sizeof vis); memset(dfn, 0, sizeof dfn); } bool spfa() { memset(dis, INF, sizeof dis); q.push(s); vis[s] = ++T; cap[s] = INF; dis[s] = 0; cur[s] = -1; while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = T - 1; for(int e = H[u]; ~e; e = E[e].next) { int v = E[e].v, c = E[e].c, w = E[e].w; if(c && dis[u] + w < dis[v]) { dis[v] = dis[u] + w; cap[v] = min(c, cap[u]); cur[v] = e; if(vis[v] != T) { vis[v] = T; q.push(v); } } } } if(dis[t] == INF) return false; flow += cap[t]; cost += cap[t] * dis[t]; for(int e = cur[t]; ~e; e = cur[E[e ^ 1].v]) { E[e].c -= cap[t]; E[e ^ 1].c += cap[t]; } return true; } int mcmf() { flow = cost = 0; while(spfa()); return cost; } void tarjan(int u) { dfn[u] = low[u] = ++dfs_clock; ss.push(u), ins[u] = true; for(int e = h[u]; ~e; e = EE[e].next) { int v = EE[e].v; if(!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if(ins[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { int t; do { t = ss.top(); ss.pop(); ins[t] = false; if(u == 0) scc[t] = true; }while(t != u); } } void work() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) { int u, v, a, b; scanf("%d%d%d%d", &u, &v, &a, &b); add_edges(u, v, a, b); } tarjan(0); int res1 = 0, res2 = 0; for(int i = 0; i < cntEE; i++) { int u = EE[i].u, v = EE[i].v, a = EE[i].a, b = EE[i].b; if(scc[u] && scc[v]) { in[v]++, out[u]++; res1 += a, res2 += b; addedges(u, v, INF, a); } } s = n + 2, t = n+1; for(int i = 0; i < n; i++) if(scc[i]) { if(out[i] > in[i]) addedges(i, t, out[i] - in[i], 0); else addedges(s, i, in[i] - out[i], 0); } res1 += mcmf(); printf("%d %d\n", res2, res1); } int main() { int _; scanf("%d", &_); while(_--) { init(); work(); } return 0; }