标签:
hdu 2544
Dijkstra
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f3f
struct Edge
{
int from,to,dist;
}Map[11000];
int a[maxn][maxn];
int d[maxn];
int visit[maxn];
int n,m;
void init()
{
memset(visit,0,sizeof(visit));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
a[i][j]=inf;
if(i==j)
a[i][j]=0;
}
for(int i=2;i<=maxn;i++)
d[i]=inf;
d[1]=0;
}
void Dijkstra()
{
for(int k=1;k<=n;k++) //循环n次是因为每次都找到了一个距离源点最近的点,n次就找完了所有距离源点最近的点,可以看成有两个集合,一个集合代表已找出距离源点最近的点,一个是还未找出的点
{
int m=inf;
int x;
for(int i=1;i<=n;i++) //暴力枚举未找出最小距离的点中的与源点相连的最小距离的点
{
if(!visit[i] && d[i]<m)
{
x=i;
m=d[i];
}
}
visit[x]=1;
for(int i=1;i<=n;i++) //更新
{
if(a[x][i]!=inf)
d[i]=min(d[i],d[x]+a[x][i]);
}
}
// for(int i=1;i<=n;i++)
// printf("%d ",d[i]);
// cout<<endl;
printf("%d\n",d[n]);
}
int main()
{
while(~scanf("%d%d",&n,&m) && n!=0 && m!=0)
{
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&Map[i].from,&Map[i].to,&Map[i].dist);
a[Map[i].from][Map[i].to]=Map[i].dist;
a[Map[i].to][Map[i].from]=Map[i].dist;
}
Dijkstra();
}
// system("pause");
return 0;
}
Dijkstra(优先队列优化,优化的是每次选取距离源点最近的点,裸的是暴力枚举)
Dijkstra使用优先队列,虽然同一个点可以多次入队(因为每个节点都可以被其他节点多次刷新),但是done数组保证了一个点真正pop出来刷新其他点的时候只有一次
当第一次出队去更新别人的时候,done[i]=true,之后判断一下就可以了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f3f3f
struct Edge
{
int from,to,dist;
};
vector <int> G[maxn*4]; //存图的编号
vector <Edge> edges;
int d[maxn];
int visit[maxn]; //标记是否在队列里
int n,m;
priority_queue < int > q;
void init()
{
for(int i=0;i<=n;i++)
G[i].clear();
edges.clear();
memset(visit,0,sizeof(visit));
for(int i=1;i<=n;i++)
d[i]=inf;
d[1]=0;
}
void AddEdge(int from,int to,int dist)
{
Edge edge;
edge.from=from; edge.to=to; edge.dist=dist;
edges.push_back(edge);
int SIZE=edges.size();
G[from].push_back(SIZE-1);
}
void Dijkstra() //由于每次出队的都是最小值,保证每个节点只进队一次。
{ //加done数组标记,如果队列里有多个相同节点的话,只让第一个去更新别人。
//Dijkstra使用优先队列,虽然同一个点可以多次入队,但是done数组保证了一个点真正pop出来刷新其他点的时候只有一次.
//pop出来就说明已经是最短路了,所以只需要更新其他的一次就可以了,跟裸的是一样的.
q.push(1);
while(!q.empty())
{
int x=q.top();
q.pop();
for(int i=0;i<G[x].size();i++)
{
Edge e=edges[G[x][i]];
if(d[e.to]>d[e.from]+e.dist)
{
d[e.to]=d[e.from]+e.dist;
q.push(e.to);
}
}
}
// for(int i=1;i<=n;i++)
// printf("%d ",d[i]);
// cout<<endl;
printf("%d\n",d[n]);
}
int main()
{
while(~scanf("%d%d",&n,&m) && n!=0 && m!=0)
{
init();
for(int i=1;i<=m;i++)
{
int from,to,dist;
scanf("%d%d%d",&from,&to,&dist);
AddEdge(from,to,dist);
AddEdge(to,from,dist);
}
Dijkstra();
}
// system("pause");
return 0;
}
Bellman_ford(图解最短路 http://www.java3z.com/cwbwebhome/article/article1/1359.html?id=4720 )
d[k][Map[i].to]=d[k-1][Map[i].from]+Map[i].dist;
#include <iostream>
#include <cstdio>
#include <cstring >
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f3f
struct Edge
{
int from,to,dist;
}Map[200010];
int d[maxn][maxn];
int n,m;
void init()
{
for(int k=0;k<maxn;k++)
for(int i=1;i<maxn;i++)
d[k][i]=inf;
for(int k=0;k<maxn;k++)
d[k][1]=0;
}
void Bellman_foyed()
{
//对每条边进行n次松弛操作
// cout<<"fsdfsd";
for(int k=1;k<=n;k++)
{
for(int i=1;i<=m;i++)
{
if(d[k-1][Map[i].from]<inf)
if(d[k-1][Map[i].from]+Map[i].dist<d[k][Map[i].to])
{
d[k][Map[i].to]=d[k-1][Map[i].from]+Map[i].dist;
}
}
}
/*for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
printf("%d ",d[k][i]);
printf("\n");
}*/
printf("%d\n",d[n][n]);
}
int main()
{
while(~scanf("%d%d",&n,&m) && n!=0 && m!=0)
{
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&Map[i].from,&Map[i].to,&Map[i].dist);
// cin>>Map[i].from>>Map[i].to>>Map[i].dist;
}
for(int i=m+1;i<=2*m;i++)
{
Map[i].to=Map[i-m].from;
Map[i].from=Map[i-m].to;
Map[i].dist=Map[i-m].dist;
}
m=2*m;
Bellman_foyed();
}
//getchar();
return 0;
}
Bellman_ford 邻接表
d[k][Map[i].to]=d[k-1][Map[i].from]+Map[i].dist;(省略了k这一维,可以理解成一个节点被其他节点刷新n次)
#include <iostream>
#include <cstdio>
#include <cstring >
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f3f
struct Edge
{
int from,to,dist;
}Map[200010];
int d[maxn];
int n,m;
void init()
{
for(int i=1;i<maxn;i++)
d[i]=inf;
d[1]=0;
}
void Bellman_foyed()
{
//对每条边进行n次松弛操作
// cout<<"fsdfsd";
for(int k=1;k<=n;k++)
{
for(int i=1;i<=m;i++)
{
if(d[Map[i].from]<inf)
if(d[Map[i].from]+Map[i].dist<d[Map[i].to])
{
d[Map[i].to]=d[Map[i].from]+Map[i].dist;
}
}
}
/*for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
printf("%d ",d[k][i]);
printf("\n");
}*/
printf("%d\n",d[n]);
}
int main()
{
while(~scanf("%d%d",&n,&m) && n!=0 && m!=0)
{
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&Map[i].from,&Map[i].to,&Map[i].dist);
// cin>>Map[i].from>>Map[i].to>>Map[i].dist;
}
for(int i=m+1;i<=2*m;i++)
{
Map[i].to=Map[i-m].from;
Map[i].from=Map[i-m].to;
Map[i].dist=Map[i-m].dist;
}
m=2*m;
Bellman_foyed();
}
//getchar();
return 0;
}
Bellman_ford 邻接矩阵(一个节点被刷新n次)
d[k][i]代表从源点经过k个点,或者说是k条边的最短距离。
d[k][i]=min(d[k][i],d[k-1][j]+a[j][i]);
#include <iostream>
#include <cstdio>
#include <cstring >
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f3f
int a[maxn][maxn];
int d[maxn][maxn][maxn];
int n,m;
void init()
{
for(int k=0;k<maxn;k++)
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
{
a[i][j]=inf;
d[k][i][j]=inf;
if(i==j)
d[k][i][j]=0;
}
}
void Bellman_foyed()
{
//对每条边进行2*m次松弛操作
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i!=j && a[j][i]!=inf)
{
if(d[k-1][1][j]+a[j][i]<d[k][1][i])
{
d[k][1][i]=d[k-1][1][j]+a[j][i];
}
}
}
}
}
/* for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
printf("%d ",d[k][1][i]);
printf("\n");
}*/
printf("%d\n",d[n][1][n]);
}
int main()
{
while(~scanf("%d%d",&n,&m) && n!=0 && m!=0)
{
init();
int from,to,dist;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&from,&to,&dist);
a[from][to]=dist;
// d[from][to]=dist;
a[to][from]=dist;
// d[to][from]=dist;
}
Bellman_foyed();
}
return 0;
}
spfa
visit数组 检查被更新的节点,保证队列里面没有相同节点,但是一个节点可以进队列多次
用SPFA的时侯,同一个节点可能会多次入队,然后多次去刷新其他节点,这样就会导致最短路条数出现重复计算(所以才可以判断负环)
当每个节点只进队列一次的话,退化成宽搜。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f3f3f
struct Edge
{
int from,to,dist;
};
vector <int> G[maxn*4]; //存图的编号
vector <Edge> edges;
int d[maxn];
int visit[maxn]; //标记是否在队列里
int n,m;
queue < int > q;
void init()
{
for(int i=0;i<=n;i++)
G[i].clear();
edges.clear();
memset(visit,0,sizeof(visit));
for(int i=1;i<=n;i++)
d[i]=inf;
d[1]=0;
}
void AddEdge(int from,int to,int dist)
{
Edge edge;
edge.from=from; edge.to=to; edge.dist=dist;
edges.push_back(edge);
int SIZE=edges.size();
G[from].push_back(SIZE-1);
}
void spfa()
{
q.push(1);
visit[1]=1;
while(!q.empty())
{
//cout<<"fsdf"<<endl;
int x=q.front();
q.pop();
visit[x]=0;
for(int i=0;i<G[x].size();i++)
{
int next_=G[x][i]; //
if(d[edges[next_].to]>d[edges[next_].from]+edges[next_].dist && d[edges[next_].from]<inf)
{
d[edges[next_].to]=d[edges[next_].from]+edges[next_].dist;
if(visit[edges[next_].to]==0)
{
visit[edges[next_].to]=1;
q.push(edges[next_].to);
}
}
}
}
//for(int i=1;i<=n;i++)
// printf("%d ",d[i]);
//cout<<endl;
printf("%d\n",d[n]);
}
int main()
{
while(~scanf("%d%d",&n,&m) && n!=0 && m!=0)
{
init();
for(int i=1;i<=m;i++)
{
int from,to,dist;
scanf("%d%d%d",&from,&to,&dist);
AddEdge(from,to,dist);
AddEdge(to,from,dist);
}
spfa();
}
// system("pause");
return 0;
}
floyd
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 110 #define inf 0x3f3f3f3f3f3f int n,m; int Map[maxn][maxn]; int d[maxn][maxn][maxn]; void init() { for(int i=0;i<maxn;i++) for(int j=0;j<maxn;j++) { Map[i][j]=inf; if(i==j) Map[i][j]=0; } } void floyd() { for(int i=0;i<maxn;i++) for(int j=0;j<maxn;j++) d[0][i][j]=Map[i][j]; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d[k][i][j]=min(d[k-1][i][j],d[k-1][i][k]+d[k-1][k][j]); /* for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%d ",d[i][j]); printf("\n"); }*/ printf("%d\n",d[n][1][n]); } int main() { while(scanf("%d%d",&n,&m) && n!=0 && m!=0) { init(); int from,to,dist; for(int i=1;i<=m;i++) { scanf("%d%d%d",&from,&to,&dist); Map[from][to]=dist; Map[to][from]=dist; } floyd(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/xianbin7/p/4666802.html