[BZOJ3597][SCOI2014][網絡流][分數規劃]方伯伯運椰子[好題]

BZOJ上沒有題幹,這裏直接貼一份:


[Description]

四川的方伯伯爲了致富,決定引進海南的椰子樹。方伯伯的椰子園十分現代化,椰子園中有一套獨特的交通系統。
現在用點來表示交通節點,邊來表示道路。這樣,方伯伯的椰子園就可以看作一個有 n + 2 個交通節點,m條邊的有向無環圖。n +1 號點爲入口,n +2 號點爲出口。每條道路都有 6 個參數,ui,vi,ai,bi,ci,di,分別表示,該道路從 ui 號點通向 vi 號點,將它的容量壓縮一次要 ai 的花費,容量擴大一次要 bi 的花費,該條道路當前的運輸容量上限爲 ci,並且每單位運輸量通過該道路要 di 的費用。
在這個交通網絡中,只有一條道路與起點相連。因爲弄壞了這條道路就會導致整個交通網絡癱瘓,聰明的方伯伯決定絕不對這條道路進行調整,也就是說,現在除了這條道路之外,對其餘道路都可以進行調整。


有兩種調整方式:
1. 選擇一條道路,將其進行一次壓縮,這條道路的容量會下降 1 單位。
2. 選擇一條道路,將其進行一次擴容,這條道路的容量會上升 1 單位。

一條道路可以被多次調整。


由於很久以前,方伯伯就請過一個工程師,對這個交通網絡進行過一次大的優化調整。所以現在所有的道路都被完全的利用起來了,即每條道路的負荷都是滿的(每條道路的流量等於其容量)。
但方伯伯一想到自己的海南椰子會大豐收,就十分擔心巨大的運輸量下,會導致過多的花費。因此,方伯伯決定至少進行一次調整,調整之後,必須要保持每條道路滿負荷,且總交通量不會減少。
設調整後的總費用是 Y,調整之前的總費用是 X。現在方伯伯想知道,最優調整比率是多少,即假設他進行了 k 次調整,(X - Y)/k最大能是多少?


注:總費用 = 交通網絡的運輸花費 + 調整的花費


[Input]

第 1 行包含 2 個整數 n,m
接下來 m 行代表 m 條邊,表示這個交通網絡。
每行 6 個整數,表示 ui,vi,ai,bi,ci,di.
接下來 1 行包含 1 條邊,表示連接起點的邊


[Output]

一個浮點數,保留 2 位小數,表示要求的答案,數據保證答案大於 0


[Sample]

樣例輸入  樣例輸出
6 7
1 2 0 0 1 1000
2 4 0 0 1 1000
4 6 0 0 1 1000
1 3 0 0 0 0
3 5 0 0 0 0
5 6 0 0 0 0
6 8 0 0 1 0
7 1 0 0 1 0
500.00

[Hint]

對於 20% 的數據, 1 <= n <= 5, 0 <= m <= 10.
對於 40% 的數據, 1 <= n <= 50, 0 <= m <= 300.
對於 100% 的數據,1 <= n <= 500,0 <= m <= 3000,1 <= ui, vi <= n + 2
0 <= ai, bi <= 50,0 <= ci <= 1000,0 <= di <= 1000


==============這裏纔是題解的開始==============

我們認爲方伯伯是在跑費用流。對於原圖中每一條邊i,建一條正向的,容量正無窮,邊權爲bi + di的邊;如果流量ci不爲0,再建一條反向的,容量爲ci,邊權爲ai - di的邊。這樣我們就構造出了殘量網絡。

這道題由於保證有大於零的解,即費用一定能減少,所以增加流量是一定沒有好下場的(費用一定增加)。那麼我們只能通過調整流量來減少費用。這個時候我們需要——

消圈定理:殘量網絡裏如果存在負費用圈,那麼當前流不是最小費用流。因爲通過增加殘量網絡負權邊的流量,減少正權邊的流量,一定能得到另一個更優的可行流。

由於這道題求的不是最優的費用流,而是最優的調整比率。所以最優解一定是隻調整一個負權環(參見分數規劃相關性質的證明自己YY去)。那麼題目變成,求平均權值最小的負權環。

沒什麼說的了,最基本的分數規劃題。

(本文是爲了打破willinglive在這道題題解上的壟斷而作。willinglive的題解地址:http://blog.csdn.net/willinglive/article/details/42772715

(話說昨年省選打醬油的時候還真是弱得1B啊,現在看來這麼簡單……)

不要隨便看代碼,不要隨便看代碼,不要隨便看代碼。因爲很重要說以說三遍

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;

//Global Variables & Definitions
int N, M;
//End Global Variables & Definitions

//Map
int h[510];

struct edge {
	int v, next;
	double w;
} e[7000];

int ecnt;
void adde(int u, int v, double w) {
	++ecnt;
	e[ecnt].v = v;
	e[ecnt].w = w;
	e[ecnt].next = h[u];
	h[u] = ecnt;
}

double dis[510];
int inq[510];
bool spfa(int n) {
	inq[n] = 1;
	
	int v;
	for(int i = h[n];~i;i = e[i].next) if(dis[v = e[i].v] > dis[n] + e[i].w) {
		dis[v] = dis[n] + e[i].w;
		
		if(inq[v]) return true;
		if(spfa(v)) return true;
	}
	
	inq[n] = 0;
	return false;
}

bool TEST() {
	for(int i = 0;i < 510;++i) { dis[i] = 0.0; inq[i] = 0; }
	
	for(int i = 1;i <= N;++i) if(spfa(i)) return true;
	return false;
}
//End Map

//Main Structure
inline void ir() {
	memset(h, ecnt = -1, sizeof(h));
	scanf("%d%d", &N, &M);
	N += 2;
	
	int u, v, a, b, c, d;
	for(int i = 0;i < M;++i) {
		scanf("%d%d%d%d%d%d", &u, &v, &a, &b, &c, &d);
		
		adde(u, v, b + d);
		if(c > 0) adde(v, u, a - d);
	}
}

const double eps = 1e-3;
int main() {
	ir();
	
	double L = 0.0, R = 1e9;
	while(R - L > eps) {
		double mid = (L + R) / 2.;
		
		for(int i = 0;i <= ecnt;++i) e[i].w += mid;
		
		if(TEST()) 
			L = mid;
		else 
		    R = mid;
		    
		for(int i = 0;i <= ecnt;++i) e[i].w -= mid;
	}
	
	printf("%.2f\n", (L + R) / 2.);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章