【UVALive】 3353 Optimal Bus Route Design 费用流

传送门:【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;
}


你可能感兴趣的:(网络流,uvalive)