POJ 1860 Currency Exchange(BellmanFord求递增环)
http://poj.org/problem?id=1860
题意:
给定你N种货币,以及M对特定货币之间的对换比率.现在你手上有货币S,问你能否通过不断地对换然后增加自己S货币的总量?
分析:
首先我们要知道只要是从货币S出发的路径上存在一个正的环,那么一定能使得初始货币S的数量无限大.
BellmanFord求得是最短路,这里我们需要求最长路.所以我们令d[i]表示从val个S货币能换取的最多的i货币数目.d[i]初值为0,d[S]=val.
松弛的情况:当 d[i]< d[j]*(1-commissions)*rate,那么就更新d[i],且要让i入队列.
那么当有节点入队次数>n时,就说明图中肯定存在从s出发能到达的递增环了。
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 100+10;
struct Edge
{
int from,to;
double r,c;
Edge(int f,int t,double r,double c):from(f),to(t),r(r),c(c){}
};
struct BellmanFord
{
int n,m;
vector<Edge> edges;
vector<int> G[maxn];
bool inq[maxn];
int cnt[maxn];
double d[maxn];
void init(int n)
{
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,double r,double c)
{
edges.push_back(Edge(from,to,r,c));
m = edges.size();
G[from].push_back(m-1);
}
bool bellman_ford(int s,double val)
{
memset(inq,0,sizeof(inq));
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++) d[i]= i==s?val:0;
queue<int> Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=0;i<G[u].size();i++)
{
Edge &e=edges[G[u][i]];
if(d[e.to] < (d[u]-e.c)*e.r)//这里的松弛条件变了
{
d[e.to] = (d[u]-e.c)*e.r;
if(!inq[e.to])
{
inq[e.to]=true;
Q.push(e.to);
if(++cnt[e.to]>n) return true;
}
}
}
}
return false;
}
}BF;
int main()
{
int n,m,s;
double v;
while(scanf("%d%d%d%lf",&n,&m,&s,&v)==4)
{
s--;
BF.init(n);
while(m--)
{
int u,v;
double r1,c1,r2,c2;
scanf("%d%d%lf%lf%lf%lf",&u,&v,&r1,&c1,&r2,&c2);
u--,v--;
BF.AddEdge(u,v,r1,c1);
BF.AddEdge(v,u,r2,c2);
}
printf("%s\n",BF.bellman_ford(s,v)?"YES":"NO");
}
return 0;
}