poj1860,poj3259,poj1062,poj2253,poj1125,poj2240
邻接矩阵(Adjacency Matrix):是表示顶点之间相邻关系的矩阵。
http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.html
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
http://blog.csdn.net/zrjdds/article/details/6728332
http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.html
STL http://blog.csdn.net/zy_dreamer/article/details/8939926
SFPA http://blog.sina.com.cn/s/blog_a46817ff01015g9h.html
http://www.cnblogs.com/hxsyl/archive/2012/07/01/2572334.html 115
*****Dijkstra-----
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0xffffff
#define M 201
int cost[M][M];//路径的权值
int d[M];//s到x最短距离
int used[M];//点是否用过
int n,m;
int s,e;//start end
int a,b,c;
void init(int v)//初始化 cost
{
for(int i=0;i<v;i++)
for(int j=0;j<v;j++)
{
cost[i][j]=INF;
}
}
void dj(int s)
{
int i,j;
for(i=0;i<=n;i++)
{
d[i]=cost[s][i];
}
used[s]=1;
d[s]=0;
/* 选其余点中距离s最短的那个点开始*/
int k,p;
for(i=0;i<=n;i++)
{
int mi=INF;
for(j=0;j<n;j++)
{
if(!used[j] && mi>d[j])
{
mi = d[j];
k = j;
}
}
used[k] = true;
for(p=0;p<n;p++)
{
if(!used[p]&&d[p]>d[k]+cost[k][p])//d[ax]+d[xb]<d[ab]不断更新dis
{
d[p]=d[k]+cost[k][p];
}
}
}
}
int main()
{
while(cin>>n>>m)
{
init(n);
for(int i=0;i<m;i++)
{
cin>>a>>b>>c;
if(cost[a][b]>c) {cost[a][b]=c;cost[b][a]=c;}//有权值的正常 没有权值的为INF
}
memset(used,0,sizeof(used));
cin>>s>>e;
dj(s);
if(d[e]<INF) cout<<d[e]<<endl;
else cout<<-1<<endl;
}
return 0;
}
**********************************************
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 0x7FFFFFFF
#define N 1005
int cls[N],map[N][N],vis[N],city[101],ans[101];
int m,n,p,q;
/*V为源点 */
void Dijkstra(int v)
{
int i,j,min,next;
/* 先用v到邻接点的距离初始化cls */
for(i=1;i<=m;i++)
cls[i]=map[v][i];
memset(vis,0,sizeof(vis));
vis[v]=1;//起点访问标志置1
for (i=1;i<m;i++)//无等号
{
min=MAX;
next=v;
/*找出离集合最近的那个点next,以及该点到集合的距离min*/
for (j=1;j<=m;j++)
{
if(!vis[j]&&cls[j]<min)
{
next=j;
min=cls[j];
}
}
vis[next]=1;
for (j=1;j<=m;j++)
{
/*j点没有被访问过,j点和next点之间有通路,next点到j点的距离+集合到nxt的距离<集合到j的距离*/
if(!vis[j]&&map[next][j]<MAX&&(min+map[next][j])<cls[j])
cls[j]=cls[next]+map[next][j];
}
}
}
int main()
{
int T,i,j;int a,b,c;int temp;
scanf("%d",&T);
while(T--)
{
temp=0x7FFFFFFF;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
map[i][j]=MAX;
scanf("%d%d%d%d",&n,&m,&p,&q);
/* 部队驻扎点 */
for(i=1;i<=n;i++)
scanf("%d",city+i);
while(p--)
{
scanf("%d%d%d",&a,&b,&c);
if(map[a][b]>c)
map[a][b]=map[b][a]=c;
}
for(i=1;i<=n;i++)
{
memset(cls,0,sizeof(cls));
Dijkstra(city[i]);
ans[i]=cls[q];
//printf("%d %d %d\n",cls[q],ans[i],cls[n]);
}
for(i=1;i<=n;i++)
if(temp>ans[i])
temp=ans[i];
printf("%d\n",temp);
}
return 0;
}
/*
error: invalid types `int[int]' for array subscript
变量和数组同名
*/
******************************************************************************************************************
#include<iostream>
#include<stdio.h>
using namespace std;
#define inf 9999999
int map[250][250];
int n,m;
int Floyd(int x,int y)
{
int t,i,j;
for(t=0; t<n; t++)
for(i=0; i<n; i++)
for(j=0; j<n; j++)
if(map[i][j]>map[i][t]+map[t][j])
{
map[i][j]=map[i][t]+map[t][j];
}
if(map[x][y]==inf) return -1;
else return map[x][y];
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int a,b,v,d,f,num;
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
map[i][j]=map[j][i]=inf;
for(int i=0; i<n; i++) //注意同一点的权值为0,刚开始wa在这儿
map[i][i]=0;
for(int i=0; i<m; i++)
{
cin>>a>>b>>v;
if(map[a][b]>v)
map[a][b]=map[b][a]=v;
}
cin>>d>>f;
num=Floyd(d,f);
cout<<num<<endl;
}
return 0;
}
******************************************************************
SPFA
算法大致流程是用一个队列来进行维护。
初始时将源加入队列。每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。直到队列为空时算法结束。
这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法
SPFA——Shortest Path Faster Algorithm,它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,可以处理负边。
SPFA的实现甚至比Dijkstra或者Bellman_Ford还要简单:
设Dist代表S到I点的当前最短距离,Fa代表S到I的当前最短路径中I点之前的一个点的编号。开始时Dist全部为+∞,只有Dist[S]=0,Fa全部为0。
维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个点S。用一个布尔数组记录每个点是否处在队列中。
每次迭代,取出队头的点v,依次枚举从v出发的边v->u,设边的长度为len,判断Dist[v]+len是否小于 Dist[u],若小于则改进Dist[u],
将Fa[u]记为v,并且由于S到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在队列中,就将它放入队尾。这样一直迭代下去直到队列变空,
也就是S到所有的最短距离都确定下来,结束算法。若一个点入队次数超过n,则有负权环。
SPFA 在形式上和宽度优先搜索非常类似,不同的是宽度优先搜索中一个点出了队列就不可能重新进入队列,
但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进,
于是再次用来改进其它的点,这样反复迭代下去。设一个点用来作为迭代点对其它点进行改进的平均次数为k,有办法证明对于通常的情况,k在2左右。
<span style="color:#339999;">/*
单源最短路径的算法最常用的是Dijkstra,些算法从时间复杂度来说为O(n^2),
但是面对含有负权植的图来说就无能为力了,此时Dellman-ford算法就有用了,
这咱算法是采用的是动态规化的思想,
但是1994年西南交通大学段凡丁发表了SPFA(Shortest Path Faster Algorithm)听这个名字就懂了,
这种算法在时间上一定很快了。它是对Dellman-ford的优化,
所以建议今后直接学SPFA。很多时候,给定的图存在负权边,
这时类似Dijkstra等算法便没有了用武之地,
而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。
我们用数组d记录每个结点的最短路径估计值,
而且用邻接表来存储图G。我们采取的方法是动态逼近法:
设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,
并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,
如果v点的最短路径估计值有所调整,
且 v点不在当前的队列中,就将v点放入队尾。
这样不断从队列中取出结点来进行松弛操作,直至队列空为止。
定理3 只要最短路径存在,上述SPFA算法必定能求出最小值。
在Bellman-Ford算法中,要是某个点的最短路径估计值更新了,
那么我们必须对所有边指向的终点再做一次松弛操作;在SPFA算法中,
某个点的最短路径估计值更新,
只有以该点为起点的边指向的终点需要再做一次松弛操作
只要最短路径存在,上述SPFA算法必定能求出最小值。*/
#include<iostream></span>
#include<algorithm>
#include<queue>
#include<stdio.h>
#include<string.h>
#define Maxn 100
#define Maxm 10000
#define Max 10000
using namespace std;
int used[Maxn],outqueue[Maxn],head[Maxn],low[Maxn],n,m;
struct Edge
{
int to,w,next;
}edge[Maxm];
int SPFA (int start)
{
queue<int>a;
used[start] = 1;
low[start] = 0;
a.push(start);
while (!a.empty())
{
int top = a.front();
a.pop();
outqueue[top]++;
if (outqueue[top] > n) return false;//用来判断是否有环路
for (int k = head[top]; k!= -1; k = edge[k].next)//宽搜每一条边
{
if (low[edge[k].to] > low[top] + edge[k].w)//对点进行松弛
low[edge[k].to] = low[top] + edge[k].w;
if (!used[edge[k].to])
{
used[edge[k].to] = 1;
a.push(edge[k].to);
}
}
}
return true;
}
int main()
{
while (scanf ("%d%d", &n ,&m) != EOF)
{
memset (used, 0 ,sizeof(used));
memset (head, -1 ,sizeof(head));
memset (outqueue, 0 ,sizeof(outqueue));
memset (low, Max, sizeof(low));
int k = 0;
while (m--)
{
int a,b,w;
scanf ("%d%d%d", &a, &b, &w);
edge[k].to = b;
edge[k].w = w;
edge[k].next = head[a];
head[a] = k++;
}
cout<<SPFA(1)<<endl;
if (SPFA(1))
printf ("%d\n", low[n]);
else
printf ("no\n");
}
}
************************************************************
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 999999
#define M 2001
int n,m,s;
int dis[M];
int vis[M];
int map[M][M];
void init()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
map[i][j]=inf;
}
}
//void dj(int s)
//{
// int i,j,k = 0;
// int min;
// memset(vis,0,sizeof(vis)); //初始时都没被访问过
// for(i = 1; i <=n; i++)
// {
// dis[i] = map[s][i];
// }
// vis[s] = 1; //第一个顶点即原点,被访问
// dis[s] = 0; //s到s 即为0
// for(i = 1; i < n; i++)
// {
// min = inf;
// //找到最小的
// for (j = 1; j <= n; j++)
// {
// if (!vis[j] && dis[j] < min)
// {
// min = dis[j];
// k = j; //最小的顶点
// }
// }
// if (min == inf)
// {
// break;
// }
// vis[k] = 1; //k顶点被访问
// //这里就是比较:直接到还是转一下再到
// //我猜,你个笨蛋肯定会问:不能转多下吗?
// //答曰:从源点一个一个向外扩展,具有最优子结构。每个dis[i]都保留着从s到i的最短距离。转多下的情况把它分解开,就知道了
// for(j = 1; j <= n; j++)
// {
// if ( !vis[j] && dis[j] > dis[k] + map[k][j])
// {
// dis[j] = dis[k] + map[k][j];
// }
// }
// }
// return ;
//}
void dj(int s)
{
int i,j,k=0;
int mi;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
dis[i]=map[s][i];
vis[s]=1;
dis[s]=0;
for(i=1;i<n;i++)
{
mi=inf;
for(j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]<mi)
{
mi=dis[j];
k=j;
}
}
if(mi==inf)
break;
vis[k]=1;
for(j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]>dis[k]+map[k][j])
{
dis[j]=dis[k]+map[k][j];
}
}
}
}
int main()
{
int p,q,t,w,ww;//起点 终点 所耗费的时间
int minx;
while(~scanf("%d%d%d",&n,&m,&s))
{
memset(dis,0,sizeof(dis));
init();//地图初始化
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&p,&q,&t);
if(t<map[q][p])
map[q][p]=t;//因为是把目的地看做源点 所以必须所有的点顺得反过来
}
dj(s);
scanf("%d",&w);
minx=inf;
for(int i=1; i<=w; i++)
{
scanf("%d",&ww);
if(minx>dis[ww])
minx=dis[ww];
}
if(minx!=inf)
printf("%d\n",minx);
else
printf("-1\n");
}
}
//void dj(int s)
//{
// int i,j,k=0;
// int mi;
// memset(vis,0,sizeof(vis));
// for(i=1; i<=n; i++)
// {
// dis[i]=map[s][i];
// }
// vis[s]=1;
// dis[s]=0;//s→s为0
// for(i=1; i<n; i++)
// {
// mi=inf;
// for(j=1; j<=n; j++)
// {
// if(!vis[j]&&dis[j]<mi)
// {
// mi=dis[j];
// k=j;
// }
// }
// if(mi=inf)
// break;
// vis[k]=1;//k被访问过
// for(j=1; j<=n; j++)
// {
// if(!vis[j]&&dis[j]>dis[k]+map[k][j])
// {
// dis[j]=dis[k]+map[k][j];
// }
// }
//
// }
// return ;
//}
最短路算法小结
最新推荐文章于 2021-05-26 16:00:28 发布