Poj 1860 Currency Exchange 【spfa算法如何判斷負權環】

負權環的判斷方法

根據鬆弛次數

n代表節點個數。

根據鬆弛次數是否大於等於n來判斷負權環,是從網上其他博客說的,根據出隊次數是否大於等於n來判斷,想到的。因爲,判斷出隊次數,是判斷更新次數的上界。

用一個n大小的數組來代表每個點的鬆弛次數。因爲SPFA算法裏的鬆弛,和Bellman-ford算法裏的鬆弛一樣。Bellman-ford算法裏,對同一個點的鬆弛次數,在極端情況下,可以想象把這些鬆弛次數分配到每一次迭代求解中去,而迭代求解一共只有n-1次。所以一旦某個點的鬆弛次數等於了n,那麼就說明有負環。

所以,在每次進行鬆弛後,遍歷判斷每個點的鬆弛次數,如果有一個等於n(再執行下去就會大於n),就說明有負環

題目解析

題目鏈接,這道題還是比較有意思的,以每種貨幣爲節點,一個兌換所提供兩條邊,我們需要找到這個圖中是否有一個環使得我們的money可以無限增多,從負環到這裏的變化,無非是改變了鬆弛條件,建好圖,利用上述的性質便可得到。

#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 105

int N, M, S, A, B, vis[MAX], num[MAX];
double V, c, a1, a2, a3, a4, mon[MAX];

struct edge {
	int to; double rate, cost;
	edge(int a = 0, double b = 0, double c = 0) { to = a, rate = b, cost = c; }
};
vector<edge> G[MAX];

void addEdge(int a,int b, double a1,double a2, double a3, double a4) {
	G[a].push_back(edge(b, a1, a2));
	G[b].push_back(edge(a, a3, a4));
}

void spfa() {
	memset(mon, 0, sizeof(mon));
	memset(vis, 0, sizeof(vis));
	memset(num, 0, sizeof(num));
	queue<int> q; q.push(S);
	mon[S] = V; vis[S] = 1;
	int cnt = -1;
	while (!q.empty()) {
		int u = q.front(); vis[u] = 0; q.pop(); num[u]++;
		if (num[u] > N) { cnt = u; break; };//存在一條可以不斷增加money的路
		//注意這裏是先num++的,因此大於N+1時才結束
		for (int i = 0; i < G[u].size(); i++) {
			edge e = G[u][i];
			if ((mon[u] - e.cost)*e.rate > mon[e.to]) {
				mon[e.to] = (mon[u] - e.cost)*e.rate;
				if (!vis[e.to]) {
					q.push(e.to);	
					vis[e.to] = 1;
				}
			}
		}
	}
	if (cnt == -1)cout << "NO" << endl;
	else cout << "YES" << endl;
}

int main() {
	while (cin >> N >> M >> S >> V) {
		//以錢幣的種類爲點
		for (int i = 1; i <= N; i++)G[i].clear();
		for (int i = 1; i <= M; i++) {
			cin >> A >> B >> a1 >> a2 >> a3 >> a4;
			addEdge(A, B, a1, a2, a3, a4);
		}
		spfa();
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章