題目鏈接
題目大意
有N(1
分析
一種貨幣看成圖上的一個結點,一種兌換方式可以看成一條邊
A到B的權值爲(Va-Cab)*Rab,注意S到S的權值爲V。
構圖完畢後可以發現題目就是要判斷圖是否構成正權迴路,所以可以逆用Bellman-Ford算法求最長路,用相反的鬆弛條件鬆弛N-1輪,如果還能繼續鬆弛則存在正權迴路。
代碼
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXM=210;
const int MAXN=110;
struct Edge
{
int beg;
int end;
double r,c;
};
Edge edge[MAXM];
int edgenum,n,m,s;
double dis[MAXN],val;
void Add_Edge(int beg,int end,double r,double c)
{
edgenum++;
edge[edgenum].beg=beg;//起點貨幣
edge[edgenum].end=end;//終點貨幣
edge[edgenum].r=r;//匯率
edge[edgenum].c=c;//手續費
}
bool Bellmen_Ford()
{
for (int i=1;i<=n;i++) dis[i]=0;//這裏與bellman的目的剛好相反。初始化爲源點到各點距離無窮小
dis[s]=val;//初始手裏的貨幣量
for (int k=1;k<=n-1;k++)//進行N-1輪鬆弛
{
bool flag=false;
for (int i=1;i<=edgenum;i++)
{
int u=edge[i].beg;
int v=edge[i].end;
if (dis[v]<(dis[u]-edge[i].c)*edge[i].r)//尋找最長路徑
{ ////進行比較的是"某點到自身的權值"和"某點到另一點的權
flag=true;
dis[v]=(dis[u]-edge[i].c)*edge[i].r;
}
}
if (!flag) return false;
}
for (int i=1;i<=edgenum;i++)//正環能夠無限鬆弛
if (dis[edge[i].end]<(dis[edge[i].beg]-edge[i].c)*edge[i].r)
return true;
return false;
}
int main()
{
int a,b;
double R_ab,C_ab,R_ba,C_ba;
while (scanf("%d%d%d%lf",&n,&m,&s,&val)!=EOF)
{
edgenum=0;
for (int i=1;i<=m;i++)
{
scanf("%d%d%lf%lf%lf%lf",&a,&b,&R_ab,&C_ab,&R_ba,&C_ba);
Add_Edge(a,b,R_ab,C_ab);
Add_Edge(b,a,R_ba,C_ba);
}
bool ans=Bellmen_Ford();
if (ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}