程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU 4411 Arrest 費用流

HDU 4411 Arrest 費用流

編輯:C++入門知識

HDU 4411 Arrest 費用流


題目鏈接:點擊打開鏈接

題意:

給定n+1個點([0,n] )m條邊的無向圖。起點為0,k個人初始在起點,

去遍歷圖使得每個點至少被一人走過且遍歷 i 點時 i-1 必須已經被遍歷。

使得k人的路徑和最小,最後k人要回到起點。

思路:

費用流,因為對於一個人來說,這個人遍歷點的序列一定是一個遞增序列(不需要連續)

所以建圖時i的出點只需要連接i+? 的入點。

若建一個完全圖則會因為spfa跑負環。。。


#include
#include
#include
#include
#include
using namespace std;
#define ll int
#define inf 1000000
#define Inf 0x3FFFFFFFFFFFFFFFLL  
#define N 250
#define M N*N*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);
	queueq;
	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 Mincost(ll s, ll t){
	ll flow = 0, cost = 0;
	while (spfa(s, t, flow, cost));
	return cost;
}
void init(){ memset(head, -1, sizeof head); edgenum = 0; }
const int MAXN = 105;
int g[MAXN][MAXN];
int n, m, k;
void floyd() {
	for (int k = 0; k <= n; k++) {
		for (int i = 0; i <= n; i++) {
			for (int j = 0; j <= n; j++) {
				if (g[i][j] > g[i][k] + g[k][j]) {
					g[i][j] = g[i][k] + g[k][j];
				}
			}
		}
	}
}
int main(){
	while (scanf("%d%d%d", &n, &m, &k) != EOF) {
		if (n == 0 && m == 0 && k == 0) break;
		for (int i = 0; i <= n; i++){
			for (int j = 0; j <= n; j++)
				g[i][j] = 10000005;
			g[i][i] = 0;
		}
		for (int i = 0, u, v, w; i < m; i++) {
			scanf("%d%d%d", &u, &v, &w);
			g[u][v] = g[v][u] = min(w, g[u][v]);
		}
		floyd();
		init();
		int to = n * 2 + 3, from = n * 2 + 2;
		for (int i = 1; i <= n; i++){
			add(0, i * 2, 1, g[0][i]);
			add(i * 2, i * 2 + 1, 1, -inf);
			add(i * 2 + 1, to, 1, g[i][0]);
			for (int j = i + 1; j <= n; j++)
				add(i * 2 + 1, j * 2, 1, g[i][j]);
		}
		add(from, 0, k, 0);
		add(0, to, k, 0);
		printf("%d\n", Mincost(from, to) + inf*n);
	}
	return 0;
}	


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved