挑战程序设计竞赛最短路习题及详解(C++实现)

Aizu - 0189 Convenient Location

弗洛伊德模板题

#include<iostream>
#include<algorithm>
using namespace std;
const int maxx=100;
#define INF 65535
int n;
int m;
int d[maxx][maxx];
void floyd()
{
	for (int k = 0; k <= m; k++)
	{
		for (int i = 0; i <= m; i++)
		{
			for (int j = 0; j <= m; j++)
			{
				d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
			}
		}
	}
}
int main()
{
	while (cin>>n&&n)
	{
		for (int i = 0; i < maxx; i++)
		{
			for (int j = 0; j < maxx; j++)
			{
				d[i][j]=INF;
			}
		}
		m=0;
		for (int i = 0; i < n; i++)
		{
			int x,y,w;
			cin>>x>>y>>w;
			m=max(m,max(x,y));
			d[x][y]=d[y][x]=w;
		}
		for (int i = 0; i <= m; i++)
		{
			d[i][i]=0;
		}
		floyd();
		int ans=INF;
		int pos=0;
		for (int i = 0; i <= m; i++)
		{
			int sum=0;
			for (int j = 0; j <= m; j++)
			{
				sum+=d[i][j];
			}
			if(sum<ans)
			{
				ans=sum;
				pos=i;
			}
		}
		cout<<pos<<' '<<ans<<endl;
	}
	return 0;
}

POJ - 2139 Six Degrees of Cowvin Bacon

同样是一道弗洛伊德模板题

#include<iostream>
#include<algorithm>
using namespace std;
const int maxx=10000+1;
#define INF 65535
int d[310][310];
int a[maxx];
int n,m;
void Floyd()
{
	for (int k = 1; k <= n; k++)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				d[i][j]=min(d[i][j],(d[i][k]+d[k][j]));
			}
		}
	}
}
int main()
{
	cin>>n>>m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			d[i][j]=INF;
			if(i==j) d[i][j]=0;
		}
	}
	for (int i = 0; i < m; i++)
	{
		int x;
		cin>>x;
		for (int j = 0; j < x; j++)
		{
			cin>>a[j];
		}
		for (int i = 0; i < x-1; i++)
		{
			for (int j = i+1; j < x; j++)
			{
				int x=a[i],y=a[j];
				d[x][y]=d[y][x]=1;
			}
		}
	}
	Floyd();
	int tot=INF;
	for (int i = 1; i <= n; i++)
	{
		int sum=0;
		for (int j = 1; j <= n; j++)
		{
			sum+=d[i][j];
		    //cout<<sum<<endl;
		}
		if (sum<tot) tot=sum;
	}
	cout<<100*(tot)/(n-1)<<endl;
	return 0;
}

POJ - 3259 Wormholes

判断有无负权环,Floyd和Ford都可以使用

#include<iostream>
#include<algorithm>
using namespace std;
#define INF 10001
const int maxx=503;
int d[maxx][maxx];
int n,m,w;
bool Floyd()
{
	for (int k = 1; k <= n; k++)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if(d[i][j]>d[i][k]+d[k][j])
				{
					d[i][j]=d[i][k]+d[k][j];
				}
			}
			if(d[i][i]<0) return 1;
			//是否存在负权环
		}
	}
	return 0;
}
int main()
{
	int p;
	cin>>p;
	while (p--)
	{
		cin>>n>>m>>w;
		memset(d,INF,sizeof(d));
		for (int i = 1; i < n; i++)
		{
			d[i][i]=0;
		}
		int x,y,z;
		for (int i = 0; i < m; i++)
		{
			cin>>x>>y>>z;
			if(z<d[x][y])
				d[x][y]=d[y][x]=z;
		}
		for (int i = 0; i < w; i++)
		{
			cin>>x>>y>>z;
			d[x][y]=-z;
		}
		if(Floyd()) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

经典的Ford模板,值得记录一下:

#include<iostream>
#include<algorithm>
using namespace std;
#define INF 10001
const int maxx=1e4;
//int d[maxx][maxx];
struct edge
{
	int s,e;
	int w;
};
edge e[maxx];
int a[maxx];
int n,m,w;
int M;
bool ford()
{
	memset(a,0,sizeof(a));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < M; j++)
		{
			int u = e[j].s;
			int v = e[j].e;
			int t = e[j].w;
			//cout<<u<<' '<<v<<' '<<t<<endl;
			if (a[v] > a[u] + t) 
			{
				a[v] = a[u] + t;
				//cout<<a[v];
				if(i==n) return 1;
			}
		}
	}
	return 0;
}
int main()
{
	int p;
	cin>>p;
	while (p--)
	{
		cin>>n>>m>>w;
		M=0;
		int x,y,z;
		for (int i = 0; i < m; i++)
		{
			cin>>x>>y>>z;
			e[M].s=x;
			e[M].e=y;
			e[M++].w=z;
			
			e[M].s=y;
			e[M].e=x;
			e[M++].w=z;
		}
		for (int i = 0; i < w; i++)
		{
			cin>>x>>y>>z;
			e[M].s=x;
			e[M].e=y;
			e[M++].w=-z;
		}/*
		for (int i = 0; i < M; i++)
		{
			cout<<e[i].s<<' '<<e[i].e<<' '<<e[i].w<<endl;
		}*/
		if(ford()) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

POJ - 3268 Silver Cow Party

逆向思维,反向建图,两次使用dijkstra,参考了大佬的代码

#include<iostream>
using namespace std;
int n,m,x;
const int maxx=1005;
#define INF 0x3f3f3f3f
int d[maxx][maxx],xd[maxx][maxx];
int a[maxx],xa[maxx];
void dij(int s[maxx][maxx],int q[maxx])
{
	bool used[maxx];
	memset(used,false,sizeof(used));
	memset(q,INF,sizeof(a));
	used[x]=0;
	for (int i = 1; i <= n; i++)
	{
		q[i]=s[x][i];
	}
	for (int i = 1; i <= n; i++)
	{
		int max=INF;
		int v=0;
		for (int j = 1; j <= n; j++)
		{
			if(!used[j]&&q[j]<max)
			{
				v=j;
				max=q[j];
			}
		}
		used[v]=true;
		for (int j = 1; j <= n; j++)
		{
			q[j]=min(q[j],q[v]+s[v][j]);
		}
	}
}
int main()
{
	cin>>n>>m>>x;
	memset(d,INF,sizeof(d));
	memset(xd,INF,sizeof(xd));
	for (int i = 1; i <= n; i++)
	{
		d[i][i]=0;
		xd[i][i]=0;
	}
	for (int i = 0; i < m; i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		d[x][y]=z;
		xd[y][x]=z;
	}
	dij(d,a);/*
	for (int i = 1; i <= n; i++)
	{
		cout<<a[i]<<' ';
	}
	cout<<endl;*/
	dij(xd,xa);
	int min=0;
	for (int i = 1; i <= n; i++)
	{
		min=max(min,a[i]+xa[i]);
	}
	cout<<min<<endl;
	return 0;
}

Aizu - 2249 Road Construction

经典的单源最短路+最小边权,针对图的邻接表利用堆优化后的dijkstra算法

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<functional>
#include<cstdio>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxa=10005;
const int maxx=50005;
struct edge
{
	int to,dis,cost;
	edge(int _to,int _dis,int _cost):to(_to),dis(_dis),cost(_cost){}
};
typedef pair<int,int> P;
int n,m;
vector<edge> G[maxx];
int d[maxa];
int cost[maxa];//cost存储的是每一步的花费,最终需要累加
void dijkstra(int s)
{
	priority_queue<P,vector<P>,greater<P> > que;
	memset(d,INF,sizeof(d));
	memset(cost,0,sizeof(cost));
	d[s]=0;
	que.push(P(0,s));
	while (!que.empty())
	{
		P p=que.top();
		que.pop();
		int v=p.second;//取出顶点编号
		if(d[v]<p.first) continue;
		for (int i = 0; i < G[v].size(); i++)
		{
			edge e=G[v][i];
			if (d[e.to]>=d[v]+e.dis)
			{
				if (d[e.to]==d[v]+e.dis)
				{
					cost[e.to]=min(cost[e.to],e.cost);
					//如果距离相等,取较小花费
				}
				else
				{
					cost[e.to]=e.cost;
					//距离不等,直接赋值
				}
				d[e.to]=d[v]+e.dis;	
				que.push(P(d[e.to],e.to));
			}
		}
	}
}
int main()
{
	while (scanf("%d%d",&n,&m)!=EOF,n+m)
	{
		for (int i = 1; i <= n; i++)
			G[i].clear();
		for (int i = 0; i < m; i++)
		{
			int x,y,z,w;
			cin>>x>>y>>z>>w;
			G[x].push_back(edge(y,z,w));
			G[y].push_back(edge(x,z,w));
		}
		dijkstra(1);
		int sum=0;
		for (int i = 1; i <= n; i++)
		{
			sum+=cost[i];
		}
		cout<<sum<<endl;
	}
	return 0;
}

总结

最短路相比较最小生成树都是图论的重要内容,变化更多,四大算法什么时候用以及优化问题还需要不断做题来积累,写题的时候参考了大佬们的代码,从中也学到了很多技巧,刷题干货满满啊。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新西兰做的饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值