传送门:【UVALive】3353 Optimal Bus Route Design
题目大意:给出一个n(n <= 100)个点的有向带权图,找若干个圈,使得每个结点恰好属于一个圈。要求总长度尽量小。注意即使有有向边(u,v)和(v,u)都存在,它们的长度也不一定相同。
题目分析:
每个点恰好属于一个圈,那么,每个点只会有一个前驱和后继,根据这个性质建图即可:
设立超级源汇,对每个点 i 拆成两个点 i、i',建边(s,i,1,0),(i',t,1,0),然后对所有有向边(i,j)建边(i,j',1,w)。跑一次最小费用最大流即可。如果流量等于点数则说明有解,反之无解。
代码如下:
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; #define Clear(A, X) memset (A, X, sizeof A) //#define Copy(A, B) memcpy (A, B, sizeof A) #define REP(I, A, B) for (int I = A; I < B: ++ I) #define FF(I, A, B) for (int I = A; I <= B; ++ I) #define Min(A, B) ((A) < (B) ? (A) : (B)) #define Max(A, B) ((A) > (B) ? (A) : (B)) const int maxN = 256; const int maxE = 1000000; const int maxQ = 1000000; const int oo = 0x3f3f3f3f; struct Edge { //int from; int to; int cap; //int rcap; int cost; int next; } edge[maxE]; int adj[maxN], cntE; int Q[maxQ], inq[maxN], head, tail; int d[maxN]; int f[maxN]; int cur[maxN]; int source, sink; int mcmf_cost, mcmf_flow; void addedge (int from, int to, int cap, int cost) { //edge[cntE].from = from; edge[cntE].to = to; edge[cntE].cap = cap; //edge[cntE].rcap = cap; edge[cntE].cost = cost; edge[cntE].next = adj[from]; adj[from] = cntE ++; //edge[cntE].from = to; edge[cntE].to = from; edge[cntE].cap = 0; //edge[cntE].rcap = 0; edge[cntE].cost = -cost; edge[cntE].next = adj[to]; adj[to] = cntE ++; } int spfa () { int u, v, cap, cost; Clear (d, oo); Clear (inq, 0); f[source] = oo; d[source] = 0; cur[source] = -1; head = tail = 0; Q[tail ++] = source; while (head != tail) { u = Q[head ++]; inq[u] = 0; for (int i = adj[u]; i != -1; i = edge[i].next) { v = edge[i].to, cap = edge[i].cap, cost = edge[i].cost; if (cap > 0 && d[v] > d[u] + cost) { d[v] = d[u] + cost; f[v] = Min(f[u], cap); cur[v] = i; if (!inq[v]) { Q[tail ++] = v; inq[v] = 1; } } } } if (d[sink] == oo) return 0; mcmf_flow += f[sink]; mcmf_cost += f[sink] * d[sink]; for (int i = cur[sink]; i != -1; i = cur[edge[i ^ 1].to]) { edge[i].cap -= f[sink]; edge[i ^ 1].cap += f[sink]; } return 1; } int MCMF () { mcmf_flow = mcmf_cost = 0; while (spfa ()) ; return mcmf_cost; } void init () { Clear (adj, -1); cntE = 0; } int n; void work () { init (); source = 0; sink = n << 1 | 1;//sink = n * 2 + 1 FF (u, 1, n) { addedge (source, u, 1, 0); addedge (u + n, sink, 1, 0); int v, cost; while (~scanf ("%d", &v) && v) { scanf ("%d", &cost); addedge (u, v + n, 1, cost); } } MCMF (); printf (mcmf_flow == n ? "%d\n" : "N\n", mcmf_cost); } int main () { while (~scanf ("%d", &n) && n) work(); return 0; }