POJ 2240 -- Arbitrage(Bellman-Ford)
题意:
已知n种货币,以及m种货币汇率及方式,问能否通过货币转换,使得财富增加。
Bellman-ford 算法:
一个具有n个顶点的图如果不存在环,则从顶点x,到顶点y,最多经过n-1条边(要考虑连通性,每个顶点最多经过 1 次),因此 x 到 y 的最短路 最多经过 n - 1 次松弛操作(就是更新长度)就应该出现,如果第 n 次松弛还可以得到最优,那么这个图就肯定是存在环了(直接用Dijkstra 就无法得到最优的,环的存在会影响最优解是否存在)。
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn = 50;//顶点的最大值 5 const int maxm = 1000;//边数的最大值 6 #define max(a,b) {(a)>(b)?(a):(b)} 7 struct node{ 8 int ci,cj; 9 double cij; 10 }exch[maxm];///兑换货币的路径 11 12 double dist[maxn];//源点到其他每个节点的最长路径,包括它本身 13 14 char name[maxn][20]; 15 int n,m; 16 bool flag; 17 int kase = 1; 18 void solve_case(int v0) 19 {//Bellman-Ford算法:以v0为源点,求它到每个顶点(包含它本身)的最大距离 20 flag = false; 21 memset(dist,0,sizeof(dist)); 22 dist[v0] = 1; 23 for(int k=1;k<=n;k++)//从dist(0)递推到dist(1)...dist(n) 进行n次松弛操作 24 { 25 for(int i=0;i<m;i++)//判断每一条边,假如他是否能使最大距离增加 26 { 27 if(dist[exch[i].ci]*exch[i].cij > dist[exch[i].cj]) 28 { 29 dist[exch[i].cj] = dist[exch[i].ci]*exch[i].cij; 30 } 31 } 32 } 33 if(dist[v0]>1.0) flag = true; 34 } 35 36 int cin_case() 37 { 38 while(cin>>n && n) 39 { 40 //输入货币的名称 ,name数组下标即为货币的编号 41 for(int i=0;i<n;i++){ 42 cin>>name[i]; 43 } 44 ///输入兑换货币的路径 45 cin>>m; 46 char a[20],b[20]; 47 double e; 48 for(int i=0;i<m;i++) 49 { 50 cin>>a>>e>>b; 51 ///得到货币的编号 52 int k,j; 53 for(k=0;strcmp(name[k],a)!=0;k++); 54 for(j=0;strcmp(name[j],b)!=0;j++); 55 ///从k->j 汇率为e 56 exch[i].ci = k;exch[i].cj = j;exch[i].cij = e; 57 } 58 return 1; 59 } 60 return 0; 61 } 62 63 int main() 64 { 65 while(cin_case()) 66 { 67 for(int i=0;i<n;i++) 68 { 69 solve_case(i);//从第i个结点出发求最长路径 70 if(flag) break; 71 } 72 if(flag) cout<<"Case "<<kase++<<": Yes"<<endl; 73 else cout<<"Case "<<kase++<<": No"<<endl; 74 } 75 76 return 0; 77 }