题目大意:
给你几个国家的货币兑换率,看你是否能通过不同国家的货币兑换之后是自己的财富增加,如增加输出YES,无法增加输出NO。
具体兑换过程:
N代表几个国家,M代表几条兑换的信息,S代表起始的国家,V代表你现有的财富金额。
从A兑换到B 得到的财富 :(V-Cab)*Rab 、
测试数据:1 2 1.00 1.00 1.00 1.00 1.00 。代表1-2兑换的Rab、Cab是1.00 1.00. 2-1的兑换的Rab和Cab是后两位浮点数1.00 1.00。
解题思路:
通过Bellman_ford 看是否有正权回路,如果有正权回路,说明财富持续增加输出YES,否则输出NO。
代码:
1 #include <algorithm> 2 #include <iostream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <string> 8 #include <bitset> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <cmath> 13 #include <list> 14 #include <map> 15 #include <set> 16 using namespace std; 17 /***************************************/ 18 #define ll long long 19 #define int64 __int64 20 /***************************************/ 21 const int INF = 0x7f7f7f7f; 22 const double eps = 1e-8; 23 const double PIE=acos(-1.0); 24 const int d1x[]= {0,-1,0,1}; 25 const int d1y[]= {-1,0,1,0}; 26 const int d2x[]= {0,-1,0,1}; 27 const int d2y[]= {1,0,-1,0}; 28 const int fx[]= {-1,-1,-1,0,0,1,1,1}; 29 const int fy[]= {-1,0,1,-1,1,-1,0,1}; 30 /***************************************/ 31 void openfile() 32 { 33 freopen("data.in","rb",stdin); 34 freopen("data.out","wb",stdout); 35 } 36 /**********************华丽丽的分割线,以上为模板部分*****************/ 37 #define MAX 0 38 #define N 9010 39 int nodenum, edgenum, w; //点,边,起点 40 typedef struct Edge //边 41 { 42 int u, v; 43 double c,r; 44 } Edge; 45 Edge edge[N]; 46 double dis[N]; 47 int d; 48 bool Bellman_Ford(int s,double w) 49 { 50 for(int i = 1; i <= nodenum; ++i) //初始化 51 dis[i]=MAX; 52 dis[s]=w; 53 for(int i = 1; i <= nodenum-1; ++i) 54 for(int j=1; j<=d-1; ++j) 55 if(dis[edge[j].u]>0&&dis[edge[j].v]<(dis[edge[j].u]-edge[j].c)*edge[j].r) //松弛(顺序一定不能反~) 56 dis[edge[j].v] =(dis[edge[j].u]-edge[j].c)*edge[j].r; 57 bool flag = 0;//判断是否含有正权回路 58 for(int j = 1; j <=d-1; ++j) 59 if(dis[edge[j].u]>0&&dis[edge[j].v]<(dis[edge[j].u]-edge[j].c)*edge[j].r) 60 { 61 flag = 1; 62 break; 63 } 64 return flag; 65 } 66 /* 67 上边是正常的判断回路,通过至少边数N-1的循环之后,再判断下各点是否能够更新dis数组,如果更新说明出现回路。 68 然而这题可以通过下面的方法做,原因是给你N条边但是实际记录的2*N条边,所以第一个for循环循环到2*N-1可以得出正确结果, 69 因为超过了N-1次循环,所以足可以判断是否有正权回路,下面的bellman_ford函数的flag是判断如果后面的循环中有任意一次没 70 进入if说明不存在正权回路,因为如果是正权回路,每一次必然会进入if。 71 bool Bellman_Ford(int s,double w) 72 { 73 for(int i = 1; i <= nodenum; ++i) //初始化 74 dis[i]=MAX; 75 dis[s]=w; 76 bool flag; 77 for(int i = 1; i <= nodenum-1; ++i) 78 { 79 flag=true; 80 for(int j=1; j<=d-1; ++j) 81 if(dis[edge[j].u]>0&&dis[edge[j].v]<(dis[edge[j].u]-edge[j].c)*edge[j].r) //松弛(顺序一定不能反~) 82 { 83 flag=false; 84 dis[edge[j].v] =(dis[edge[j].u]-edge[j].c)*edge[j].r; 85 } 86 if (flag) 87 return false; 88 } 89 return true; 90 } 91 */ 92 int main() 93 { 94 int u,v; 95 double c,r; 96 int s; 97 double w; 98 while(scanf("%d%d%d%lf", &nodenum, &edgenum,&s,&w)!=EOF) 99 { 100 d=1; 101 for(int i = 1; i <= edgenum; ++i) 102 { 103 scanf("%d%d%lf%lf",&u,&v,&r,&c); 104 edge[d].u=u; 105 edge[d].v=v; 106 edge[d].c=c; 107 edge[d].r=r; 108 d++; 109 scanf("%lf%lf",&r,&c); 110 edge[d].u=v; 111 edge[d].v=u; 112 edge[d].c=c; 113 edge[d].r=r; 114 d++; 115 } 116 if(Bellman_Ford(s,w)) 117 printf("YES "); 118 else 119 printf("NO "); 120 } 121 return 0; 122 }