[数据结构] 货币套汇(图路径)

题目描述

套汇是指利用货币汇兑率的差异将一个单位的某种货币转换为大于一个单位的同种货币。例如,假定1 美元可以买0.7 英镑,1 英镑可以买9.5 法郎,1法郎可以买到0.16美元。通过货币兑换,一个商人可以从1 美元开始买入,得到0.7×9.5×0.16=1.064美元,从而获得6.4%的利润。 给定n种货币c1 ,c2 ,… ,cn的有关兑换率,试设计一个有效算法,确定货币间是否存在套汇的可能性。

提示:判断图上是否出现正环,即环上所有的边相乘大于1

输入

第一行:测试数据组数

每组测试数据格式为:

第一行:正整数n (1< =n< =30),正整数m,分别表示n种货币和m种不同的货币兑换率。

2~n+1行,n种货币的名称。

n+2~n+m+1行,每行有3 个数据项ci,rij 和cj ,表示货币ci 和cj的兑换率为 rij。

输出

对每组测试数据,如果存在套汇的可能则输出YES

如果不存在套汇的可能,则输出NO。

示例输入

2
3 3
USDollar
BritishPound
FrenchFranc
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar
3 6
USDollar
BritishPound
FrenchFranc
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar

示例输出

YES
NO

思路
判断图上是否出现正环,即环上所有的边相乘大于1。对所有点都进行一次深度优先搜索;在搜索过程中,如果能回到初始点形成环,则判断边乘积是否大于1;是则标记为可以套汇,否则继续往下搜索。

参考代码

#include <iostream>

using namespace std;

#define MAX_NUM 20

class AdjMatrix
{
private:
    double matrix[MAX_NUM][MAX_NUM];
    string node[MAX_NUM];
    int node_num;
    int arc_num;
    int conn_num;
    double value; ///路径汇率乘积
    int flag; ///是否能套汇
    char type;
    int Visit[MAX_NUM];
    void DFS(int v);
public:
    AdjMatrix(char ty, int n)
    {
        type = ty;
        node_num = n;
        conn_num=0;
        flag=0;
    }
    int getIndex(string s);
    void getMatrix();
    void display();
    void DFSTraverse();
};

int AdjMatrix::getIndex(string s)
{
    for(int i=0; i<node_num; i++)
    {
        if(node[i]==s)
            return i;
    }
    return -1;
}

void AdjMatrix::getMatrix()
{
    for(int i=0; i<node_num; i++)
        for(int j=0; j<node_num; j++)
            matrix[i][j] = 0;

    cin>>arc_num;
    for(int i=0; i<node_num; i++)
    {
        string s1;
        cin>>s1;
        node[i] = s1;
    }
    for(int i=0; i<arc_num; i++)
    {
        string s1, s2;
        double currency;
        int index1, index2;
        cin>>s1;
        cin>>currency;
        cin>>s2;
        index1 = getIndex(s1);
        index2 = getIndex(s2);
        if(type=='D')
        {
            matrix[index1][index2] = currency;
        }
        else if(type=='U')
        { ///这题用不到
            matrix[index1][index2]++;
            matrix[index2][index1]++;
        }
    }
}

void AdjMatrix::DFSTraverse()
{
    int v, k;
    int i;


    for(k=0; k<node_num; k++)
    {
        int counter=0;
        value=1.0;
        v=k;
        for(i=0; i<node_num; i++)
        {
            if(i==v)
                Visit[i] = 2; ///表示起始点
            else
                Visit[i] = 0;
        }

        do
        {
            //cout<<"v="<<v<<" ";
            if(Visit[v]==0 || Visit[v]==2)
            {
                counter++;
                if(counter>1) break; //表示从该点出发无法形成环,直接跳过
                DFS(v);
            }
            v = (v+1) % node_num;
        }while(v!=k);
        //cout<<endl;
        //cout<<counter<<endl;
    }

    if(flag==1)
        cout<<"YES";
    else
        cout<<"NO";
    cout<<endl;
}

void AdjMatrix::DFS(int v)
{
    int w, i, k;
    //cout<<node[v]<<"->";
    if(Visit[v]==0)
        Visit[v]=1;

    int *AdjVex = new int[node_num];
    for(i=0; i<node_num; i++)
        AdjVex[i] = -1;

    k = 0; ///寻找其相邻的点
    for(i=0; i<node_num; i++)
    {
        if(matrix[v][i]!=0) ///小心
        {
            AdjVex[k] = i;
            k++;
        }
    }

    i=0;
    for(w=AdjVex[0]; w!=-1; w=AdjVex[i])
    { ///访问其所有相邻的点
        if(Visit[w]==0)
        {
            value = value*matrix[v][w];
            DFS(w);
        }

        else if(Visit[w]==2) //如果可以回到初始点形成环
        {
            double temp_value = value; //判定边乘积是否大于1
            temp_value = temp_value*matrix[v][w];
            //cout<<temp_value<<endl;
            if(temp_value>1.0)
            {
                flag = 1;
            }
        }
        i++;
    }

    delete []AdjVex;
}

void AdjMatrix::display()
{
    int i, j;
    for(i=0; i<node_num; i++)
    { ///输出点
        cout<<node[i];
        if(i!=node_num-1)
                cout<<"\t";
    }
    cout<<endl;

    for(i=0; i<node_num; i++)
    {
        for(j=0; j<node_num; j++)
        {
            cout<<matrix[i][j];
            if(j!=node_num-1)
                cout<<"\t";
        }
        cout<<endl;
    }
    //cout<<conn_num<<endl;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        //char ty;
        int n;
        cin>>n;
        AdjMatrix test('D', n);
        test.getMatrix();
        //test.display();
        test.DFSTraverse();
        //cout<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值