POJ [1860]外貨両替[正の電源ループの判断]

説明文

私たちの街ではいくつかの両替所が働いています。各ポイントが2つの特定の通貨に特化し、これらの通貨でのみ交換操作を実行するとします。同じ通貨ペアに特化したポイントがいくつかあります。各ポイントには独自の為替レートがあり、AからBへの為替レートは、1Aに対して取得するBの数量です。また、各交換ポイントにはコミッションがあり、交換操作に支払う必要のある金額です。手数料は常に元の通貨で徴収されます。
たとえば、為替レートが29.75で、手数料が0.39である交換ポイントで100米ドルをロシアルーブルに交換する場合、(100-0.39)* 29.75 = 2963.3975RURになります。
あなたは確かにあなたが私たちの街で扱うことができるNの異なる通貨があることを知っています。1からNまでの一意の整数を各通貨に割り当てます。その通貨交換の数、実- A整数およびB:各交換点は6つの数字で記述することができR_A_BタクシーR_B_A およびC_B_A それぞれAとBと為替レートと手数料交換A及びB - 。
ニックは通貨Sでいくらかお金を持っています、そして彼が何らかの交換操作の後に彼の資本を増やすことができるかどうか疑問に思います。もちろん、彼は最後に通貨Sでお金を持ちたいと思っています。彼がこの難しい質問に答えるのを助けてください。ニックは彼の操作をしている間、常に負でない金額を持っている必要があります。

入力 

入力の最初の行には4つの数値が含まれています。N-通貨の数、M-交換ポイントの数、S-Nickが持っている通貨の数、V-彼が持っている通貨単位の数。次のM行には、6つの数字(対応する交換ポイントの説明)が上記の順序で含まれています。番号は1つ以上のスペースで区切られます。1 <= S <= N <= 100、1 <= M <= 100、Vは実数、0 <= V <= 10 ^ 3です。
各ポイントの為替レートと手数料は実数で、小数点以下最大2桁の10 ^-^ 2<= rate <= 10 ^ 2、0 <= commission <= で示され10 ^ 2ます。
このシーケンスで交換ポイントが2回以上使用されない場合、交換操作のシーケンスを単純なものと呼びます。交換操作の単純なシーケンスの最後と最初の合計の数値の比率は、より小さいと想定できます10 ^ 4

出力 

ニックが富を増やすことができる場合は、YESを出力します。それ以外の場合は、出力ファイルにNOを出力します。

入力例

3 2 1 20.0 
1 2 1.00 1.00 1.00 1.00 
2 3 1.10 1.00 1.10 1.00

出力例

はい

主なアイデア:

複数の通貨があり、両替が可能であると同時に手数料がかかります。100 AコインをBコインに交換するとき、AからBへの交換レートが29.75で、手数料が0.39の場合、(100-0.39)* 29.75 = 2963.3975 Bコインを獲得できます。交換回数無制限でSコインの枚数を増やしてもらえるかと聞かれました。

分析:

通貨はグラフ上のポイントと見なすことができ、「交換ポイント」はグラフ上の2つの通貨間のエッジです。

、Bに対するAの重量辺の重みを考慮  (V-C_A_B)* R_A_BAに、Bと右側値  (V-C_B_A)* R_B_A

Sコインの最終的な量を増やすこと、つまり図で正の回路を見つけることが必要です。さらに、このサーキットにSを含める必要はありません。このサーキットに十分なラップがある限り、金額の増加は常に最終的なSコインの増加を保証できるためです。

したがって、Bellman-Fordを使用してグラフに正のリングがあるかどうかを判断でき、緩和条件を変更するだけで済みます。

具体的な説明については、コードを参照してください。

//#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <cmath>
#include <vector>
#include <iomanip>

using namespace std;

const int maxn=10005;
const int INF=0x3f3f3f3f;

double dis[maxn];

int ans;
int m,n,s;
double initv;

struct node{
    int u,v;
    double r,c;
}edge[maxn];

void add(int u,int v,double r,double c){
	ans++;
    edge[ans].u=u;
    edge[ans].v=v;
    edge[ans].r=r;
    edge[ans].c=c;
}

bool Bellman_Ford(){
	memset(dis,0,sizeof(dis));	//初始化其他点的dis值为0 
	dis[s]=initv;
	bool flag;
	for(int i=1;i<=n-1;i++){
		flag=false;
		for(int j=1;j<=ans;j++)
			if(dis[edge[j].v] < (dis[edge[j].u] - edge[j].c) * edge[j].r){   //与求最短路的松弛条件正好相反                                                              
				dis[edge[j].v] = (dis[edge[j].u] - edge[j].c) * edge[j].r;
				flag=true;
			}
		if(!flag) break;	//若已经不再更新,则直接跳出 
	}
	for(int k=1;k<=ans;k++)                                          
		if(dis[edge[k].v] < (dis[edge[k].u] - edge[k].c) * edge[k].r)           //正环能够无限松弛,所以如果跳出后仍能发生更新,则存在正环 
			return true;
	return false;
}

int main(){
	int a,b;
	double rab,cab,rba,cba;
	ans=0;
	cin>>n>>m>>s>>initv;
	for(int i=1;i<=m;i++){
		cin>>a>>b>>rab>>cab>>rba>>cba;
		add(a,b,rab,cab);	//保存两个方向的边 
		add(b,a,rba,cba);
	}
	if(Bellman_Ford())  cout<<"YES"<<endl;
	else  cout<<"NO"<<endl;
	return 0;
}


 

 

公開された30元の記事 ウォンの賞賛5 ビュー900

おすすめ

転載: blog.csdn.net/qq_42840665/article/details/101917310