题目大意:有n种货币,给出m种兑换方式,问nick能不能用手中的S型货币,经过一系列兑换后赚钱
输入:n m s s型货币的个数V(1<=s<=n<=100, 1<=m<=100, 0<=V<=103)
a b Rab Cab Rba Cba(共m行 a b两种货币的兑换汇率以及手续费)
输出:YES/NO
分析:用bellman-ford算法(讲解详见http://blog.sina.com.cn/s/blog_7058524b0101a8gu.html)变相求最大路径,和poj2240(多源)很像。用这个算法的原因是这种货币兑换问题是存在负权路的,所以不能用Dijkstra等算法来做,否则会出现某一大路径加一负值路径小于小路径的情况,求不出最终结果,而bellman算法是可以判断带负权权值的图中是否存在负权回路的,当松弛n次时还能继续变大说明存在正环(本题其实就是判断是否有正环)。
还可以用spfa算法(队列优化的最短路径算法),就是效率更高的bellman算法。
代码:转载自http://blog.youkuaiyun.com/lyhvoyage/article/details/19281013
方法一:bellman-ford算法。
- #include<stdio.h>
- #include<string.h>
- int n, m, s, C;
- double v, dis[110];
- struct point
- {
- int a, b;
- double rate, cost;
- }p[500];
- bool Bellman_Ford()
- {
- memset(dis, 0, sizeof(dis)); //此处与Bellman-Ford的处理相反,初始化为源点到各点距离0,到自身的值为原值
- dis[s] = v;
- for(int i = 1; i <= n - 1; i++)
- {
- bool flag = false;
- for(int j = 0; j < C; j++)
- {
- int a = p[j].a, b = p[j].b;
- double r = p[j].rate, c = p[j].cost;
- if(dis[b] < (dis[a] - c) * r)
- {
- dis[b] = (dis[a] - c) * r;
- flag = true;
- }
- }
- if(!flag)
- break;
- }
- for(int i = 0; i < C; i++)
- if(dis[p[i].b] < (dis[p[i].a] - p[i].cost) * p[i].rate) //正环能够无限松弛
- return true;
- return false;
- }
- int main()
- {
- int i, j, a, b;
- double rab, rba, cab, cba;
- while(~scanf("%d%d%d%lf",&n,&m,&s,&v))
- {
- C = 0;
- for(i = 0; i < m; i++)
- {
- scanf("%d%d%lf%lf%lf%lf",&a, &b, &rab, &cab, &rba, &cba);
- p[C].a = a;
- p[C].b = b;
- p[C].rate = rab;
- p[C++].cost = cab;
- p[C].a = b;
- p[C].b = a;
- p[C].rate = rba;
- p[C++].cost = cba;
- }
- if(Bellman_Ford())
- printf("YES\n");
- else
- printf("NO\n");
- }
- return 0;
- }
- #include<stdio.h>
- #include<string.h>
- #include<queue>
- using namespace std;
- const int N = 110;
- int n, m, s;
- double dis[N], v, rate[N][N], cost[N][N];
- bool spfa(int start)
- {
- bool inq[110];
- memset(inq, 0, sizeof(inq));
- memset(dis, 0, sizeof(dis));
- dis[start] = v;
- queue<int> Q;
- Q.push(start);
- inq[start] = true;
- while(!Q.empty())
- {
- int x = Q.front();
- Q.pop();
- inq[x] = false;
- for(int i = 0; i <= n; i++) //这里试一试能不能将0改成1
- {
- if(dis[i] < (dis[x] - cost[x][i]) * rate[x][i])
- {
- dis[i] = (dis[x] - cost[x][i]) * rate[x][i];
- if(dis[start] > v)
- return true;
- if(!inq[i])
- {
- Q.push(i);
- inq[i] = true;
- }
- }
- }
- }
- return false;
- }
- int main()
- {
- int i, j;
- while(~scanf("%d%d%d%lf",&n,&m,&s,&v))
- {
- int a, b;
- double rab, rba, cab, cba;
- for(i = 1; i <= n; i++)
- for(j = 1; j <= n; j++)
- {
- if(i == j)
- rate[i][j] = 1;
- else
- rate[i][j] = 0;
- cost[i][j] = 0;
- }
- for(i = 0; i < m; i++)
- {
- scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
- rate[a][b] = rab;
- rate[b][a] = rba;
- cost[a][b] = cab;
- cost[b][a] = cba;
- }
- if(spfa(s))
- printf("YES\n");
- else
- printf("NO\n");
- }
- return 0;
- }