HDU 1217 Arbitrage (Floyd + SPFA判环)

题目链接:HDU 1217 Arbitrage


简单的货币转换问题,给定多种货币,以及货币之间的汇率,问能否通过货币的转换实现收益。

例如:

1 US Dollar buys 0.5 British pound, 1 British pound buys 10.0 French francs, and 1 French franc buys 0.21 US dollar. Then, by converting currencies, a clever trader can start with 1 US dollar and buy 0.5 * 10.0 * 0.21 = 1.05 US dollars, making a profit of 5 percent.


【解法1】

Floyd算法。

Floyd算法可以求任意两点的最短距离, 这里通过小小的变形。求最大”收益“;

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
double maze[40][40];
int main(){
    int cas=1;
    int n;
    while(scanf("%d",&n)!=EOF && n){
        char tmp[30];
        map<string,int>mp;
        for(int i=0;i<n;i++){
            scanf(" %s",tmp);
            mp[tmp] = i;
        }
        int m;
        scanf("%d",&m);
        char st[30],end[30];
        double rate;
        memset(maze,0,sizeof(maze)); //初始化为 0 
        maze[0][0] = 1; //起点为1;
        for(int i=0;i<m;i++){
            scanf(" %s%lf%s",st,&rate,end);
            maze[mp[st]][mp[end]] = rate;
        }
        for(int k=0;k<n;k++){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(maze[i][j] < maze[i][k] * maze[k][j]){ //这里是乘法,看是否通过汇率转换实现增大本金;
                        maze[i][j] = maze[i][k] * maze[k][j];
                    }
                }
            }
        }
        cout<<"Case "<<cas++<<": ";
        if(maze[0][0] > 1){
            cout<<"Yes"<<endl;
        }
        else 
            cout<<"No"<<endl;
    }
    return 0;
}

【解法2】

SPFA 判环 ,如果起点可以通过汇率转换增大。那么在SPFA的松弛操作中会无限加入队列,判断是否重复加入n次以上即可。

和我上一篇博客的解法一致。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
double maze[40][40];
const int maxn = 40;
double dis[maxn]; //记录各个种类money的当前值,初始化为0 ,起点为1;
bool vis[maxn]; //标记是否在队列之中
int cnt[maxn]; //判环
int n;
int SPFA(){
	queue<int>Q;
	Q.push(0); vis[0]=1; dis[0] = 1;cnt[0]++;
	while(!Q.empty()){
		int now = Q.front(); Q.pop(); vis[now] = false;
		for(int i=0;i<n;i++){
			double rate = maze[now][i];
			if(dis[i] < dis[now] * rate) //如果可以增大
			{
				dis[i] = dis[now] * rate;
				if(!vis[i]){
					vis[i]=1;
					Q.push(i);
				}
				if(++cnt[i] > n){ //如果节点加入队列超过n次
					return -1;
					
			}
		}
	}
	return 1;
}
void init(){
	memset(vis,0,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	memset(dis,0,sizeof(dis));
}
int main(){
	int cas=1;
		map<string,int>mp;
	while(scanf("%d",&n)!=EOF && n){
		char tmp[30];
		mp.clear();
		for(int i=0;i<n;i++){
			scanf(" %s",tmp);
			mp[tmp] = i;
		}
		int m;
		scanf("%d",&m);
		char st[30],end[30];
		double rate;
		init();
		maze[0][0] = 1;
		for(int i=0;i<m;i++){
			scanf(" %s%lf%s",st,&rate,end);
			maze[mp[st]][mp[end]] = rate;
		}
		int ret = SPFA();
		cout<<"Case "<<cas++<<": ";
		if(ret == -1)
			cout<<"Yes"<<endl;
		else 
			cout<<"No"<<endl;
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值