利用这三个题目学习理解了一下bellman——ford 算法
poj2240:给出不同货币之间的汇率,求是否可以通过货币的多次兑换使得最终得到的货币比开始时多。其实就是求是否存在无限增大的环。
#include <iostream>
#include <string>
#include <string.h>
#include <cstdio>
using namespace std;
const int maxn=10000;
int V,E;
int n,m;
double d[maxn];
typedef struct edge
{
int from,to;
double cost ;
};
struct edge es[maxn];
char s1[1000][1000],s2[1000],s3[1000];
bool bellman_ford()
{
for(int i=0; i<n; i++) d[i]=0;
d[0]=1;
for(int i=0; i<n; i++)
{
for(int j=0;j<m;j++)
{
edge e = es[j];
if(d[e.to]<d[e.from]*e.cost)
{
d[e.to]=d[e.from]*e.cost;
}
}
}
for(int i=0; i<m; i++)
{
edge e = es[i];
if(d[e.to]<d[e.from]*e.cost)
{
return true;
}
}
return false;
}
int main ()
{
int kase=1;
while(scanf("%d",&n)!=EOF&&n)
{
E=0;
memset(s1,0,sizeof(s1));
for(int i=0; i<n; i++)
{
scanf("%s",s1[i]);
}
scanf("%d\n",&m);
double rate;;
for(int i=0; i<m; i++)
{
scanf("%s %lf %s",s2,&rate,s3);
int k,l;
for(int k=0; k<n; k++)
{
if(!strcmp(s1[k],s2))
{
es[E].from=k;
break;
}
}
for(int k=0; k<n; k++)
{
if(!strcmp(s1[k],s3))
{
es[E].to=k;
break;
}
}
es[E].cost=rate;
E++;
}
// for(int i=0;i<E;i++)
// {
// printf("%d %lf %d\n" ,es[i].from,es[i].cost,es[i].to);
// }
if(bellman_ford()) printf("Case %d: Yes\n",kase++);
else printf("Case %d: No\n",kase++);
}
return 0;
}
poj 1860:和上一题差不多,也是求给出汇率,求是否存在无限增大的环。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=105;
const int E=205;
const double MAX=99999999;
struct Edge
{
int beg;
int end;
double r,c;
};
Edge edge[E];
double mindis[N];
int n,m,e,fn;
double fv;
void addedge(int beg,int end,double r,double c)
{
edge[e].beg=beg;
edge[e].end=end;
edge[e].r=r;
edge[e].c=c;
++e;
}
bool relax (int pe)
{
double t=(mindis[edge[pe].beg]-edge[pe].c)*edge[pe].r;
if(t>mindis[edge[pe].end])
{
mindis[edge[pe].end]=t;
return true;
}
return false;
}
bool bellman_ford()
{
bool flag;
for(int i=0;i<n;i++) mindis[i]=0.0;
mindis[fn]=fv;
for(int i=0;i<n-1;i++)
{
flag=false;
for(int j=0;j<e;j++)
{
if(relax(j)) flag=true;
}
if(mindis[fn]>fv) return true;
if(!flag) return false;
}
for(int i=0;i<e;i++)
{
if(relax(i)) return true;
}
return false;
}
int main ()
{
int beg,end;
double r1,r2,c1,c2;
scanf("%d%d%d%lf",&n,&m,&fn,&fv);
--fn;
e=0;
for(int i=0;i<m;i++)
{
scanf("%d%d%lf%lf%lf%lf",&beg,&end,&r1,&c1,&r2,&c2);
--beg;
--end;
addedge(beg,end,r1,c1);
addedge(end,beg,r2,c2);
}
bool ans=bellman_ford();
if(ans) printf("YES\n");
else printf("NO\n");
return 0;
}
poj 3259:题意大概是,虫洞:农夫约翰有F个农场,每个农场有N块地,其间有M条路,W条时光隧道(时间倒流)。问是否可能回到过去?
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int map[505][505],n,m,k,num=0;
int floyd()
{
int i,j,k,f=0;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)
{
int t=map[i][k]+map[k][j];
if(map[i][j]>t)map[i][j]=t;
/*map[i][j]=min(map[i][j],map[i][k]+map[k][j]);*/
}
if(map[i][i]<0)return 1;
}
return f;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int i,j,a,b,c;
scanf("%d%d%d",&n,&m,&k);
memset(map,0x3f3f3f3f,sizeof(map));
for(i=1;i<=n;i++)map[i][i]=0;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(c<map[a][b])map[a][b]=map[b][a]=c;
}
for(i=1;i<=k;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=-c;
}
num++;
int f=floyd();
if(!f)printf("NO\n");
else printf("YES\n");
}
return 0;
}
通过这三股题目,初步理解了一下bellman的思想,发现大多数利用bellman的时候都是存在负权回路的时候。