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 ; //}