目录
poj 2387 Til the Cows Come Home
poj 2387 Til the Cows Come Home
题意:求起点到终点的最短距离。
bellman_ford算法:需要考虑重边。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 2e3+10;
const int INF = 0x3f3f3f3f;
typedef struct node{
int to,from,ed;
}Node;
Node no[Max];
int V,E;
int d[Max];
void bellman_ford(int s)
{
memset(d,0x3f,sizeof(d));
d[s]=0;
while(true)
{
bool update = false;
for(int i=0;i<E;i++)
{
node e = no[i];
if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.ed){
d[e.to]=d[e.from]+e.ed;
update = true;
}
if(d[e.to]!=INF&&d[e.from]>d[e.to]+e.ed){
d[e.from]=d[e.to]+e.ed;
update = true;
}
}
if(!update) break;
}
}
int main()
{
//freopen("input.txt","r",stdin);
cin>>E>>V;
for(int i=0;i<E;i++)
cin>>no[i].from>>no[i].to>>no[i].ed;
bellman_ford(1);
cout<<d[V]<<endl;
return 0;
}
poj 2253 Frogger
题意:起点到终点所有路径中最大跳跃距离的最小值。
核心在floyd 的变换方程:mp[i][j]=min(mp[i][j],max(mp[i][k],mp[k][j]));
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
double mp[210][210];
double cal(int x1,int y1,int x2,int y2)
{
return sqrt(double(x1-x2)*(x1-x2)+double(y1-y2)*(y1-y2));
}
void floyd(int n)
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
//起点到终点所有路径中最大跳跃距离的最小值
mp[i][j]=min(mp[i][j],max(mp[i][k],mp[k][j]));
}
int main()
{
int n,x[210],y[210];
int Case=1;
// freopen("input.txt","r",stdin);
while(cin>>n&&n)
{
memset(mp,0,sizeof(mp));
for(int i=0;i<n;i++)
cin>>x[i]>>y[i];
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
mp[i][j]=mp[j][i]=cal(x[i],y[i],x[j],y[j]);
}
}
floyd(n);
printf("Scenario #%d
Frog Distance = %.3lf
",Case++,mp[0][1]);
printf("
");
}
return 0;
}
void Dijkstra(int n)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) dis[i]=INF;
dis[1]=0;
for(int i=1;i<=n;i++)
{
int minn = INF ,k;
for(int j=1;j<=n;j++)
{
if(vis[j]==0 && dis[j]<minn){
k = j;
minn = dis[j];
}
}
vis[k]=1;
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],max(dis[k],mp[k][j]));
}
}
poj 1797 Heavy Transportation
题意:n条公路,要把物品从公路1运送到公路n 每条路都有其最大承载量 要求将物品从1运到N的过程,一次所能运的最多的货物
即:求从顶点1到顶点n的 所有可行路径中 各边权值的最小值的最大值
和poj 2253类似,但这道题用floyd会T
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 1e3+10;
int mp[Max][Max];
int vis[Max],dis[Max];
void Dijkstra(int n,int m)
{
for(int i=1;i<=n;i++)
{
dis[i]=mp[1][i];
vis[i]=0;
}
int Max,v;
for(int i=1;i<=n;i++)
{
Max = -1;
for(int j=1;j<=n;j++)
{
if(!vis[j] && dis[j]>Max)
{
Max=dis[j];
v = j;
}
}
vis[v] = 1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]<min(dis[v],mp[v][j] ) )
dis[j] = min(dis[v],mp[v][j]);
}
}
}
int main()
{
int T;
int n,m,x,y,z;
int Case = 1;
// freopen("input.txt","r",stdin);
cin>>T;
while(T--)
{
cin>>n>>m;
memset(mp,0,sizeof(mp));
for(int i=0;i<m;i++)
{
cin>>x>>y>>z;
mp[x][y]=mp[y][x]=z;
}
Dijkstra(n,m);
printf("Scenario #%d:
",Case++);
cout<<dis[n]<<endl;
cout<<endl;
}
return 0;
}
注意:求最大当中的最小(poj2253),和求最小当中的最大(poj1797),dis的初始值不一样。
poj 3268 Silver Cow Party
题意:有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。
每头牛返回的最短时间很简单就可以算出来,这相当于从目标牛为起点求单源最短路径。但每头牛出发到目标牛的最短时间无法直接算出来,稍微转换一下,发现这个最短时间其实可以通过把所有的边取反向,然后再从目标牛求一次单源最短路径得到。得到这两个最短路径之后,取它们的和的最大者即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int Max = 1e3+10;
int N,M,X;
int cost[Max][Max];
int vis[Max],dis[Max],bdis[Max];
void Dijkstra()
{
for(int i=1;i<=N;i++)
{
vis[i]=0;
dis[i]=cost[X][i];
bdis[i]=cost[i][X];
}
for(int i=1;i<=N;i++)
{
int mi=INF,v;
for(int j=1;j<=N;j++)
{
if(!vis[j]&&dis[j]<mi){
mi=dis[j];
v = j;
}
}
vis[v]=1;
for(int j=1;j<=N;j++)
{
if(vis[j]==0)
dis[j]=min(dis[j],dis[v]+cost[v][j]);
}
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=N;i++)
{
int mi=INF,v;
for(int j=1;j<=N;j++)
{
if(!vis[j]&&bdis[j]<mi){
mi=bdis[j];
v = j;
}
}
vis[v]=1;
for(int j=1;j<=N;j++)
{
if(vis[j]==0)
bdis[j]=min(bdis[j],bdis[v]+cost[j][v]);
//注意这个地方,现在是反着走,cost不要写成cost[v][j]了,这里WA了一下午
}
}
int ma = -1;
for(int i=1;i<=N;i++)
{
if(dis[i]+bdis[i]>ma)
ma = dis[i]+bdis[i];
}
cout<<ma<<endl;
}
int main()
{
int from,to;
cin>>N>>M>>X;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(i==j) cost[i][j]=0;
else
cost[i][j]=INF;
for(int i=1;i<=M;i++)
{
cin>>from>>to;
cin>>cost[from][to];
}
Dijkstra();
return 0;
}
poj 1860 Currency Exchange
题意:输入n,m,s,v分别代表:有n种货币,有m个地方可以进行货币交换, 你起始的货币种类,你起始货币种类的数目 循环m次接下来输入a,b,rab,cab,rba,cba分别代表a——>b交换 rab:把a换成b的汇率,cab:a换成b的手续费; 问经过重复的交换是否可以使初始货币的总量增加
分析:一种货币就是一个点一个“兑换点”就是图上两种货币之间的一个 兑换方式,是双边,但A到B的汇率和手续费可能与B到A的汇率和手续费不同。 唯一值得注意的是权值,当拥有货币A的数量为V时,A到A的权值为K,即没有兑换 而A到B的权值为(V-Cab)*Rab本题是“求最大路径”,之所以被归类为“求最小路径” 是因为本题题恰恰与bellman-Ford算法的松弛条件相反,求的是能无限松弛的最大正 权路径,但是依然能够利用bellman-Ford的思想去解题。 因此初始化dis(S)=V 而源点到其他点的距离(权值)初始化为无穷小(0), 当s到其他某点的距离能不断变大时,说明存在最大路径;如果可以一直变大, 说明存在正环。判断是否存在环路
注意:要两次使用floyd。第一次用,是本金经过其他总换点的兑换,其他币的价值,并且存下来;
第二次用floyd算法,是为了,和第一个用,作比较,看看其他币种的价值是否增加,如果是,那么判断是正权回路;这么做的目的,判断正权回路,不单单是经过源点的正权回路,还有其他币种的正权回路;
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int Max = 105;
int n,m,s;
double mp[Max],C[Max][Max],R[Max][Max],v;
//mp[]存的是权值 (mp[]-Cab)*Rab
int floyd()
{
double dis[Max];
for(int i=1;i<=n;i++) dis[i] = mp[i];
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if((mp[i]-C[i][j])*R[i][j] > mp[j])
mp[j]=(mp[i]-C[i][j])*R[i][j];
for(int i=1;i<=n;i++)//判断有无正环
if(dis[i]<mp[i])
return 1;
return 0;
}
int main()
{
int a,b;
double c,d,e,f;
cin>>n>>m>>s>>v;
memset(mp,0,sizeof(mp));
memset(R,0,sizeof(R));
memset(C,0,sizeof(C));
for(int i=1;i<=m;i++)
{
cin>>a>>b>>c>>d>>e>>f;
R[a][b]=c;C[a][b]=d;
R[b][a]= e;C[b][a]=f;
}
mp[s]=v;
floyd();
if(floyd()) printf("YES
");
else printf("NO
");
return 0;
}
hdu 3790 最短路径问题
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int Max = 1e3+10;
const int INF = 0x3f3f3f3f;
int V,E;
struct node{
int from,to,ed,cost;
};
node no[100010];
int dis[Max],spent[Max];
void bellman(int s)
{
memset(dis,0x3f,sizeof(dis));
memset(spent,0,sizeof(spent));
dis[s]=0;
while(true)
{
bool update = false;
for(int i=0;i<E;i++)
{
node e = no[i];
if(dis[e.to]>dis[e.from]+e.ed){
dis[e.to]=dis[e.from]+e.ed;
spent[e.to]=spent[e.from]+e.cost;
update = true;
} else if((dis[e.to]==dis[e.from]+e.ed)&&(spent[e.to]>spent[e.from]+e.cost)){
spent[e.to]=spent[e.from]+e.cost;
update = true;
}
if(dis[e.from]>dis[e.to]+e.ed){
dis[e.from]=dis[e.to]+e.ed;
spent[e.from]=spent[e.to]+e.cost;
update = true;
}else if((dis[e.from]==dis[e.to]+e.ed)&&(spent[e.from]>spent[e.to]+e.cost)){
spent[e.from]=spent[e.to]+e.cost;
update = true;
}
}
if(!update) break;
}
}
int main()
{
while(~scanf("%d%d",&V,&E)){
if(V==0&&E==0) break;
for(int i=0;i<E;i++)
scanf("%d%d%d%d",&no[i].from,&no[i].to,&no[i].ed,&no[i].cost);
int s,en;
scanf("%d%d",&s,&en);
bellman(s);
printf("%d %d
",dis[en],spent[en]);
}
return 0;
}