【I - Arbitrage】

博客围绕SPFA算法展开,介绍了SLF和LLL优化。对比了邻接矩阵和邻接表下不同算法及优化组合的性能,得出邻接表更快、Bell比SPFA快、SLF和LLL使时间增加等结论,还阐述了正权单向找正环的思路及代码运行时间和内存情况。

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

写在前面的话:关于SLF(斯拉夫)和LLL(treple long)优化(自己用的昵称),详见QAQqwe的BLOG

总结:

  1. 本题先后写了:
    邻接矩阵:BellSPFASPFA+SLF;
    邻接表:SPFASPFA+SLFSPFA+SLFSPFA+SLF+LLL

  2. 结论:(仅针对我自己,我也不知道为什么大家都是SPFA更快,我也不知道为什么大家都可以做到SLF和LLL的优化)

    邻接表要快一些。

    BellSPFA快。

    SLF和LLL都让时间增加。 SPFA+SLF+LLL一定T

思路:

  • 正权,单向,找正环(最长路)。
  • SPFA:队列中存的是 id
  • SLF优化:
    1. 最重要的是 Q.size(),没它一定 RE
    2. 最短路中,dis 小放前面;最长路中:dis 大放前面。

代码:

  • BELL:735ms 712kB
//735ms		712kB


#include <iostream>
#include <algorithm>
#include <string>
#include <map>

using namespace std;

const int maxn = 35;

int T=0;
int N;
map<string,int> MP;
int M;
double exmp[maxn][maxn];
double dis[maxn];

void INIT(){
	for(int i=1;i<maxn;i++){
		for(int j=1;j<maxn;j++)
			exmp[i][j]=0;
		exmp[i][i] = 1;
	}
	MP.clear();
	for(int i=1;i<maxn;i++)
		dis[i]=0;
} 

bool BELL(){
	dis[1] = 1;
	int t;
	for(t=1;t<=N;t++){
		bool flag = false;
		for(int i=1;i<=N;i++){
			for(int j=1;j<=N;j++){
				if(dis[j] < dis[i] * exmp[i][j]){
					dis[j] = dis[i] * exmp[i][j];
					flag = true;
				}
			}
		}
		if(!flag)
			break;
	}
	if(t>N)
		return true;
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N && N){
		T++;
		INIT();
		for(int i=1;i<=N;i++){
			string name;
			cin>>name;
			if(!MP.count(name))
				MP[name] = i;
		}
		cin>>M;
		for(int i=1;i<=M;i++){
			string A,B;
			double rate;
			cin>>A>>rate>>B;
			exmp[MP[A]][MP[B]] = max(exmp[MP[A]][MP[B]] , rate);
		}
		if(BELL())
			cout<<"Case "<<T<<": "<<"Yes"<<endl;
		else
			cout<<"Case "<<T<<": "<<"No"<<endl;
	}
	return 0;
}
  • SPFA:797ms 728kB
//797ms		728kB


#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <map>

using namespace std;

const int maxn = 35;

int T;
int N,M;
map<string,int> MP;
queue<int> D;
double dis[maxn];
bool vis[maxn];
int cnt[maxn];
double exmp[maxn][maxn];

void INIT(){
	MP.clear();
	while(D.size())
		D.pop();
	for(int i=1;i<maxn;i++)
		dis[i] = 0,cnt[i] = 0,vis[i]=0;
	for(int i=1;i<maxn;i++)
		for(int j=1;j<maxn;j++)
			exmp[i][j] = 0;
	return ;
}

bool SPFA(){
	dis[1] = 1;
	D.push(1);vis[1] = true;
	while(D.size()){
		int cur = D.front() ; D.pop();vis[cur]=0;
		for(int i=1;i<=N;i++){
			if(exmp[cur][i])
				if(dis[i] < dis[cur] * exmp[cur][i]){
					dis[i] = dis[cur] * exmp[cur][i];
					if(!vis[i]){
						D.push(i);
						cnt[i]++;
						if(cnt[i] == N)
							return true;
						vis[i] = true;
					}
				}
		}
	}
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N && N){
		T++;
		INIT();
		for(int i=1;i<=N;i++){
			string name;
			cin>>name;
			MP[name] = i;
		}
		cin>>M;
		for(int i=1;i<=M;i++){
			string A,B;
			double rate;
			cin>>A>>rate>>B;
			exmp[MP[A]][MP[B]] = max(exmp[MP[A]][MP[B]] , rate);
		}
		if(SPFA())
			cout<<"Case "<<T<<": "<<"Yes"<<endl;
		else
			cout<<"Case "<<T<<": "<<"No"<<endl;
	}
	return 0;
}
  • SPFA+SLF:844ms 740kB
//844ms		740kB 


#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <map>

using namespace std;

const int maxn = 35;

int T;
int N,M;
map<string,int> MP;
deque<int> D;
double dis[maxn];
bool vis[maxn];
int cnt[maxn];
double exmp[maxn][maxn];

void INIT(){
	MP.clear();
	while(D.size())
		D.pop_front();
	for(int i=1;i<maxn;i++)
		dis[i] = 0,cnt[i] = 0,vis[i]=0;
	for(int i=1;i<maxn;i++)
		for(int j=1;j<maxn;j++)
			exmp[i][j] = 0;
	return ;
}

bool SPFA(){
	dis[1] = 1;
	D.push_front(1);vis[1] = true;
	while(D.size()){
		int cur = D.front() ; D.pop_front();vis[cur]=0;
		for(int i=1;i<=N;i++){
			if(exmp[cur][i])
				if(dis[i] < dis[cur] * exmp[cur][i]){
					dis[i] = dis[cur] * exmp[cur][i];
					if(!vis[i]){
						if(D.size() && dis[i] < dis[D.front()])
							//注意D.size()不加会RE 
							D.push_front(i);
						else
							D.push_back(i);
						cnt[i]++;
						if(cnt[i] == N)
							return true;
						vis[i] = true;
					}
				}
		}
	}
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N && N){
		T++;
		INIT();
		for(int i=1;i<=N;i++){
			string name;
			cin>>name;
			MP[name] = i;
		}
		cin>>M;
		for(int i=1;i<=M;i++){
			string A,B;
			double rate;
			cin>>A>>rate>>B;
			exmp[MP[A]][MP[B]] = max(exmp[MP[A]][MP[B]] , rate);
		}
		if(SPFA())
			cout<<"Case "<<T<<": "<<"Yes"<<endl;
		else
			cout<<"Case "<<T<<": "<<"No"<<endl;
	}
	return 0;
}
  • 邻接表+SPFA:750ms 752kB
//750ms		752kB


#include <iostream>
#include <queue>
#include <algorithm>
#include <string>
#include <map>

using namespace std;

const int maxn = 305;

int T=0;
int N,M;
deque<int> Q;
map<string,int> MP;//name & id
struct EDGE{
	int to;
	double  r;
	int fo;
};
EDGE E[maxn * 10];
int tail[maxn];
double dis[maxn];
bool vis[maxn];
int cnt[maxn];

void ADDEDGE(int i,int u,int v,double w){
	E[i].to = v;
	E[i].r = w;
	E[i].fo = tail[u];
	tail[u] = i;
	return ;
}

void INIT(){
	for(int i=1;i<maxn;i++)
		tail[i] = -1 , dis[i] = 0 , vis[i] = 0 , cnt[i] = 0;
	
}

bool SPFA(){
	dis[1] = 1;
	Q.push_back(1);vis[1] = 1;
	while(Q.size()){
		int cur = Q.front();Q.pop_front();vis[cur]=0;
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] < dis[cur] * E[i].r){
				dis[v] = dis[cur] * E[i].r;
				if(!vis[v]){
					Q.push_back(v);vis[v]=1;
					cnt[v]++;
					if(cnt[v] == N)
						return true;
				}
			}
		}
	}
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N && N){
		T++;
		INIT();
		for(int i=1;i<=N;i++){
			string name;
			cin>>name;
			MP[name] = i;
		}
		cin>>M;
		for(int i=1;i<=M;i++){
			string A,B;
			double r;
			cin>>A>>r>>B;
			ADDEDGE(i , MP[A] , MP[B] , r);
		}
		if(SPFA())
			cout<<"Case "<<T<<": "<<"Yes"<<endl;
		else
			cout<<"Case "<<T<<": "<<"No"<<endl;
	}
	return 0;
}
  • 邻接表+SPFA+SLF:782ms 736kB
//782ms		736kB


#include <iostream>
#include <queue>
#include <algorithm>
#include <string>
#include <map>

using namespace std;

const int maxn = 305;

int T=0;
int N,M;
deque<int> Q;
map<string,int> MP;//name & id
struct EDGE{
	int to;
	double  r;
	int fo;
};
EDGE E[maxn * 10];
int tail[maxn];
double dis[maxn];
bool vis[maxn];
int cnt[maxn];

void ADDEDGE(int i,int u,int v,double w){
	E[i].to = v;
	E[i].r = w;
	E[i].fo = tail[u];
	tail[u] = i;
	return ;
}

void INIT(){
	for(int i=1;i<maxn;i++)
		tail[i] = -1 , dis[i] = 0 , vis[i] = 0 , cnt[i] = 0;
	
}

bool SPFA(){
	dis[1] = 1;
	Q.push_back(1);vis[1] = 1;
	while(Q.size()){
		int cur = Q.front();Q.pop_front();vis[cur]=0;
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to;
			if(dis[v] < dis[cur] * E[i].r){
				dis[v] = dis[cur] * E[i].r;
				if(!vis[v]){
					vis[v]=1;
					if(Q.size() && dis[Q.front()] < dis[v])
						Q.push_front(v);
					else
						Q.push_back(v);
					cnt[v]++;
					if(cnt[v] == N)
						return true;
				}
			}
		}
	}
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N && N){
		T++;
		INIT();
		for(int i=1;i<=N;i++){
			string name;
			cin>>name;
			MP[name] = i;
		}
		cin>>M;
		for(int i=1;i<=M;i++){
			string A,B;
			double r;
			cin>>A>>r>>B;
			ADDEDGE(i , MP[A] , MP[B] , r);
		}
		if(SPFA())
			cout<<"Case "<<T<<": "<<"Yes"<<endl;
		else
			cout<<"Case "<<T<<": "<<"No"<<endl;
	}
	return 0;
}
  • 邻接表+SPFA+SLF+LLL:TLE
//TLE


#include <iostream>
#include <queue>
#include <algorithm>
#include <string>
#include <map>

using namespace std;

const int maxn = 305;

int T=0;
int N,M;
deque<int> Q;
map<string,int> MP;//name & id
struct EDGE{
	int to;
	double  r;
	int fo;
};
EDGE E[maxn * 10];
int tail[maxn];
double dis[maxn];
bool vis[maxn];
int cnt[maxn];
double sum;

void ADDEDGE(int i,int u,int v,double w){
	E[i].to = v;
	E[i].r = w;
	E[i].fo = tail[u];
	tail[u] = i;
	return ;
}

void INIT(){
	for(int i=1;i<maxn;i++)
		tail[i] = -1 , dis[i] = 0 , vis[i] = 0 , cnt[i] = 0;
	return ;
}

bool SPFA(){
	dis[1] = 1;
	Q.push_back(1);vis[1] = 1;sum = 1;
	while(Q.size()){
		int cur = Q.front();
		int num = Q.size();
		while(dis[cur] * num < sum){
			Q.pop_front();
			Q.push_back(cur);
			cur = Q.front();
		}
		Q.pop_front();
		vis[cur]=0;
		sum -= dis[cur];
		for(int i=tail[cur] ; ~i ; i=E[i].fo){
			int v = E[i].to; 
			if(dis[v] < dis[cur] * E[i].r){
				dis[v] = dis[cur] * E[i].r;
				if(!vis[v]){
					vis[v]=1;
					if(Q.size() && dis[Q.front()] < dis[v])
						Q.push_front(v);
					else
						Q.push_back(v);
					sum += dis[v];
					cnt[v]++;
					if(cnt[v] == N)
						return true;
				}
			}
		}
	}
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>N && N){
		T++;
		INIT();
		for(int i=1;i<=N;i++){
			string name;
			cin>>name;
			MP[name] = i;
		}
		cin>>M;
		for(int i=1;i<=M;i++){
			string A,B;
			double r;
			cin>>A>>r>>B;
			ADDEDGE(i , MP[A] , MP[B] , r);
		}
		if(SPFA())
			cout<<"Case "<<T<<": "<<"Yes"<<endl;
		else
			cout<<"Case "<<T<<": "<<"No"<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值