poj1860(图论,bellman-ford)

传送门:poj1860

题意:有多种货币和多个货币兑换处,每个货币兑换处能将确定的两种货币互相兑换,但要收取一定的手续费,给你一种初始货币和一定的数量问你能不能经过兑换后使其数量变多。最后要换回初始的货币种类。

货币兑换公式:Vb=(Va-Cab)*Rab.

将每种货币看为一个点,一种货币能兑换兑换成另一种就在这两个点之间加一条边,即每个货币兑换处能在两个点之间形成一个环,要使货币增值就是看整个图中有没有正权回路,即Bellman-ford算法的逆运用,将初始货币代表的点到其他点的距离初始化为0,到自己的距离为初始货币数量,有正权回路即能无限松弛。将Bellman-ford算法中判断负权回路的条件和松弛的条件改为小于即可。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct node{
	int p,q;
	double r,c;
}ex[202];
int n,m,s;
double v; 
double dis[101];
int rebellman_ford()
{
	memset(dis,0,sizeof(dis));
	dis[s]=v;
	int flag=0;
	for(int i=1;i<=n-1;i++)
	{
		for(int j=0;j<2*m;j++)
		{
			if(dis[ex[j].q]<(dis[ex[j].p]-ex[j].c)*ex[j].r)//如果通过q换成p能让p的数量变多则更新
			{
				dis[ex[j].q]=(dis[ex[j].p]-ex[j].c)*ex[j].r;
				flag=1;
			}
		}
		if(!flag)
		break;
		flag=0;
	}
	for(int i=0;i<2*m;i++)//判断n-1次松弛之后是否还有两个点能继续松弛
	if(dis[ex[i].q]<(dis[ex[i].p]-ex[i].c)*ex[i].r)
	return 1;
	return 0; 
	
}
int main()
{

	int p,q;
	double a,b,c,d;
	int cnt=0;
	scanf("%d%d%d%lf",&n,&m,&s,&v);
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%lf%lf%lf%lf",&p,&q,&a,&b,&c,&d);
		ex[cnt].p=p;
		ex[cnt].q=q;
		ex[cnt].r=a;
		ex[cnt++].c=b;
		ex[cnt].p=q;
		ex[cnt].q=p;
		ex[cnt].r=c;
		ex[cnt++].c=d;
	 }
	 if(rebellman_ford())
	 printf("YES\n");
	 else
	 printf("NO\n");
	 
return 0;
}

后来又做了一遍这个题,写了spfa,但是竟然比原来还慢。。而且内存还高。。好气啊

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
struct node{
	int v;
	double r,c;
};
int n,m,s;
double v;
vector<node>mp[105];
void rebellman()
{
	queue<int>q;
	while(!q.empty())
	q.pop();
	int book[105];
	double dis[105];
	memset(book,0,sizeof(book));
	memset(dis,0,sizeof(dis));
	dis[s]=v;
	book[s]=1;
	q.push(s);
	int cnt[105]={0},flag=1;
	while(!q.empty()&&flag)
	{
		int u=q.front();
		q.pop();
		book[u]=0;
		int k=mp[u].size();
		for(int i=0;i<k;i++)
		{
			int v=mp[u][i].v;
			double w=(dis[u]-mp[u][i].c)*mp[u][i].r;
			if(dis[v]<w)
			{
				dis[v]=w;
				if(!book[v])
				{
					q.push(v);
					book[v]=1;
					cnt[v]++;
					if(cnt[v]>=n)//若某个点入队次数大于n-1,则说明有正环
					{
						flag=0;
					}
				}				
			}
		}			
	}
	if(flag)
	printf("NO\n");
	else
	printf("YES\n");
}
int main()
{
	
	while(~scanf("%d%d%d%lf",&n,&m,&s,&v))
	{
		for(int i=0;i<105;i++)
		mp[i].clear();
		int a,b;
		double c,d,e,f;
		node t;
		for(int i=0;i<m;i++)
		{
			scanf("%d%d%lf%lf%lf%lf",&a,&b,&c,&d,&e,&f);
			t.c=d;t.r=c;t.v=b;
			mp[a].push_back(t);
			t.c=f;t.r=e;t.v=a;
			mp[b].push_back(t);
		}
		rebellman();
	}
return 0;
}

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/lxy767087094/article/details/52759955
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞