【E - Currency Exchange】

博客围绕货币兑换问题展开,将N种货币视为N个地点,M家银行看作M条路,通过找最长路来判断回到原点能否获得更多钱,还需判断是否存在正环。作者尝试了BELLMAN - FORD和SPFA算法,运行时间相同,对SPFA中vis[i]++位置判断存疑,写SLF后时间无变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:

-啊,做得好懵…

  • N种货币就是N个地点,M家“银行”就是M条路,找最长路,使用 i-th 货币时可以得到的最多钱就是 dis[i]。判断最后回到原点时可不可以得到更多钱。并且要判断是否有正环,如果有正环就能得到无限多的钱。
  • 可是写的BELLMAN-FORDSPFA运行时间完全一样啊…
  • SPFA中对于 vis[i]++ 位置的判断也不知道是否正确。
  • 甚至当我写了一个SLF,时间没有丝毫变化…就没有耐心写LLL了,改题再写吧。

代码:

  • Bellman-Ford:141ms 688kB
//141ms		688kB


#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 105;

//径: 
int M;
struct node{ 
	int U,V;
	double ru,su;//rate,submission 
	double rv,sv;
};
node NODE[maxn];
void addnode(int i,int U,int V,double ru,double su,double rv,double sv){
	NODE[i].U = U;
	NODE[i].V = V;
	NODE[i].ru = ru;
	NODE[i].rv = rv;
	NODE[i].su = su;
	NODE[i].sv = sv;
	return ;
}
//点: 
int N;
int S;
double V;
double dis[maxn];//记录换成i-th种货币时最多能得到多少钱 

bool BellmanFord(){
	for(int i=1;i<=N;i++)
		dis[i] = 0 ;
	dis[S] = V;
	int t;
	for(t=1;t<=N;t++){
		//(点数-1)次松弛,安排
		bool book = 0;
		for(int i=1;i<=M;i++){
			//遍历边 
			if(dis[NODE[i].V] < (dis[NODE[i].U] - NODE[i].su) * NODE[i].ru){
				dis[NODE[i].V] = (dis[NODE[i].U] - NODE[i].su) * NODE[i].ru;
				book = 1;
			}
			if(dis[NODE[i].U] < (dis[NODE[i].V] - NODE[i].sv) * NODE[i].rv){
				dis[NODE[i].U] = (dis[NODE[i].V] - NODE[i].sv) * NODE[i].rv;
				book = 1;
			}
		}
		if(!book)
			break;
	}
	if(t > N)
		return true ; //有正环,可以无限增大
	if(dis[S] > V)
		return true ;
	return false;
}

int main(){
	cin>>N>>M>>S>>V;
	for(int i=1;i<=M;i++){
		int a,b;double c,d,e,f;
		cin>>a>>b>>c>>d>>e>>f;
		addnode(i,a,b,c,d,e,f);
	}
	if(BellmanFord())
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
}
  • SPFA:关于 vis[i]++ 的两种形式:141ms
//141ms		680kB


#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 105;

//点:
int N,S;
double V;
double dis[maxn];
int vis[maxn];//记录点的入队次数 
bool book[maxn];//记录点是否在队列中 
struct NODE{
	int id;
	int dis;
	NODE(int id,int dis) : id(id) , dis(dis) {} ; 
}; 
deque<NODE> D;
//径: 
int M;
struct PATH{
	int a,b;
	double ra,sa,rb,sb;
};
PATH P[maxn];
void addpath(int i,int a,int b,double c,double d,double e,double f){
	P[i].a = a;
	P[i].b = b;
	P[i].ra = c;
	P[i].sa = d;
	P[i].rb = e;
	P[i].sb = f;
	return ;
}

bool SPFA(){
	for(int i=1;i<=N;i++)
		dis[i]=0,vis[i]=0;
	D.push_back(NODE(S,V));vis[S]=1;dis[S]=V;book[S]=true;
	while(D.size()){
		NODE cur = D.front();D.pop_front();book[cur.id]=false;
		for(int i=1;i<=M;i++){
			if(P[i].a == cur.id){
				if(dis[P[i].b] < (dis[P[i].a] - P[i].sa) * P[i].ra){
					dis[P[i].b] = (dis[P[i].a] - P[i].sa) * P[i].ra;
					if(!book[P[i].b]){
						D.push_back(NODE(P[i].b , dis[P[i].b]));
						book[P[i].b] = true;
						vis[P[i].b]++;
						//为什么队列中有点时仅更新不加松弛次数:
							//因为无法修改队列中已有的点,可能会有某些点被同一个点反复松弛。 
							//但是,我把vis[P[i].b]++放到判断外面也AC了,姑且认为是数据不强,若以后弄明白会再来补。 
						if(vis[P[i].b] == N)
							return true;
					}
				}
			}
			if(P[i].b == cur.id){
				if(dis[P[i].a] < (dis[P[i].b] - P[i].sb) * P[i].rb){
					dis[P[i].a] = (dis[P[i].b] - P[i].sb) * P[i].rb;
					if(!book[P[i].a]){
						D.push_back(NODE(P[i].a , dis[P[i].a]));
						book[P[i].a] = true;
						vis[P[i].a]++;
						if(vis[P[i].a] == N)
							return true;
					} 
				}
			}
		}
	}
	if(dis[S] != V)
		return true;
	return false;
}

int main(){
	cin>>N>>M>>S>>V;
	for(int i=1;i<=M;i++){
		int a,b;
		double c,d,e,f;
		cin>>a>>b>>c>>d>>e>>f;
		addpath(i,a,b,c,d,e,f);
	}
	if(SPFA())
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
}
//141ms		676kB


#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

const int maxn = 105;

//点:
int N,S;
double V;
double dis[maxn];
int vis[maxn];//记录点的入队次数 
bool book[maxn];//记录点是否在队列中 
struct NODE{
	int id;
	double *dis;
	NODE(int id,double *dis) : id(id) , dis(dis) {} ; 
}; 
deque<NODE> D;
//径: 
int M;
struct PATH{
	int a,b;
	double ra,sa,rb,sb;
};
PATH P[maxn];
void addpath(int i,int a,int b,double c,double d,double e,double f){
	P[i].a = a;
	P[i].b = b;
	P[i].ra = c;
	P[i].sa = d;
	P[i].rb = e;
	P[i].sb = f;
	return ;
}

bool SPFA(){
	for(int i=1;i<=N;i++)
		dis[i]=0,vis[i]=0;
	D.push_back(NODE(S,&dis[S]));vis[S]=1;dis[S]=V;book[S]=true;
	while(D.size()){
		NODE cur = D.front();D.pop_front();book[cur.id]=false;
		for(int i=1;i<=M;i++){
			if(P[i].a == cur.id){
				if(dis[P[i].b] < (dis[P[i].a] - P[i].sa) * P[i].ra){
					dis[P[i].b] = (dis[P[i].a] - P[i].sa) * P[i].ra;
					vis[P[i].b]++;
					if(!book[P[i].b]){
						D.push_back(NODE(P[i].b , &dis[P[i].b]));
						book[P[i].b] = true;
						if(vis[P[i].b] == N)
							return true;
					}
				}
			}
			if(P[i].b == cur.id){
				if(dis[P[i].a] < (dis[P[i].b] - P[i].sb) * P[i].rb){
					dis[P[i].a] = (dis[P[i].b] - P[i].sb) * P[i].rb;
					vis[P[i].a]++;
					if(!book[P[i].a]){
						D.push_back(NODE(P[i].a , &dis[P[i].a]));
						book[P[i].a] = true;
						vis[P[i].a]++;
						if(vis[P[i].a] == N)
							return true;
					} 
				}
			}
		}
	}
	if(dis[S] != V)
		return true;
	return false;
}

int main(){
	cin>>N>>M>>S>>V;
	for(int i=1;i<=M;i++){
		int a,b;
		double c,d,e,f;
		cin>>a>>b>>c>>d>>e>>f;
		addpath(i,a,b,c,d,e,f);
	}
	if(SPFA())
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值