shortest path
单源最短路径
单终点最短路径问题
单对顶点最短路径问题
每队顶点的最短路径
最短路径有最优子结构
即使存在负权值的边只要没有从源点可达的负权值回路就存在最短路径。
1.Bellman-Ford可以检查并报告出这种回路的存在
负权回路:回路中权值相加为负值就为负权回路
正权回路:不存在最短路径
0权回路:可以去掉,然后变成一个无环图
图G=(V,E)包含最多V个不同顶点,|V|-1条边
2.dag有向无环图
先进行拓扑排序,然后松弛
可以
pert-chart分析中确定关键路径,--要完成工作的最长时间 把正无穷-》负无穷,然后>改成<
单源最短路径采用的是临接表
每队顶点的最短距离采用的是临接矩阵
floyd算法思想:
1 void floyd() { 2 for(int i=1; i<=n ; i++){ 3 for(int j=1; j<= n; j++){ 4 if(map[i][j]==Inf){ 5 path[i][j] = -1;//表示 i -> j 不通 6 }else{ 7 path[i][j] = i;// 表示 i -> j 前驱为 i 8 } 9 } 10 } 11 for(int k=1; k<=n; k++) { 12 for(int i=1; i<=n; i++) { 13 for(int j=1; j<=n; j++) { 14 if(!(dist[i][k]==Inf||dist[k][j]==Inf)&&dist[i][j] > dist[i][k] + dist[k][j]) { 15 dist[i][j] = dist[i][k] + dist[k][j]; 16 path[i][k] = i; 17 path[i][j] = path[k][j]; 18 } 19 } 20 } 21 } 22 } 23 void printPath(int from, int to) { 24 /* 25 * 这是倒序输出,若想正序可放入栈中,然后输出。 26 * 27 * 这样的输出为什么正确呢?个人认为用到了最优子结构性质, 28 * 即最短路径的子路径仍然是最短路径 29 */ 30 while(path[from][to]!=from) { 31 System.out.print(path[from][to] +""); 32 to = path[from][to]; 33 } 34 }
Bellman_Ford
1 void floyd() { 2 for(int i=1; i<=n ; i++){ 3 for(int j=1; j<= n; j++){ 4 if(map[i][j]==Inf){ 5 path[i][j] = -1;//表示 i -> j 不通 6 }else{ 7 path[i][j] = i;// 表示 i -> j 前驱为 i 8 } 9 } 10 } 11 for(int k=1; k<=n; k++) { 12 for(int i=1; i<=n; i++) { 13 for(int j=1; j<=n; j++) { 14 if(!(dist[i][k]==Inf||dist[k][j]==Inf)&&dist[i][j] > dist[i][k] + dist[k][j]) { 15 dist[i][j] = dist[i][k] + dist[k][j]; 16 path[i][k] = i; 17 path[i][j] = path[k][j]; 18 } 19 } 20 } 21 } 22 } 23 void printPath(int from, int to) { 24 /* 25 * 这是倒序输出,若想正序可放入栈中,然后输出。 26 * 27 * 这样的输出为什么正确呢?个人认为用到了最优子结构性质, 28 * 即最短路径的子路径仍然是最短路径 29 */ 30 while(path[from][to]!=from) { 31 System.out.print(path[from][to] +""); 32 to = path[from][to]; 33 } 34 }
Dijkstra
1 const int MAXINT = 32767; 2 const int MAXNUM = 10; 3 int dist[MAXNUM]; 4 int prev[MAXNUM]; 5 6 int A[MAXUNM][MAXNUM]; 7 8 void Dijkstra(int v0) 9 { 10 bool S[MAXNUM]; // 判断是否已存入该点到S集合中 11 int n=MAXNUM; 12 for(int i=1; i<=n; ++i) 13 { 14 dist[i] = A[v0][i]; 15 S[i] = false; // 初始都未用过该点 16 if(dist[i] == MAXINT) 17 prev[i] = -1; 18 else 19 prev[i] = v0; 20 } 21 dist[v0] = 0; 22 S[v0] = true; 23 for(int i=2; i<=n; i++) 24 { 25 int mindist = MAXINT; 26 int u = v0; // 找出当前未使用的点j的dist[j]最小值 27 for(int j=1; j<=n; ++j) 28 if((!S[j]) && dist[j]<mindist) 29 { 30 u = j; // u保存当前邻接点中距离最小的点的号码 31 mindist = dist[j]; 32 } 33 S[u] = true; 34 for(int j=1; j<=n; j++) 35 if((!S[j]) && A[u][j]<MAXINT) 36 { 37 if(dist[u] + A[u][j] < dist[j]) //在通过新加入的u点路径找到离v0点更短的路径 38 { 39 dist[j] = dist[u] + A[u][j]; //更新dist 40 prev[j] = u; //记录前驱顶点 41 } 42 } 43 } 44 }
Kruskal hhhhhh 无向联通图的最小生成树,节点:n 边 n*(n-1)/2
hhhhh kruskal算法详解。
uva,117
给出街道的名字,第一个字母和最后一个字母代表节点,
此无向图为欧拉回路,当所有节点的度都为偶数的时候,直接走一次就能过一次回路,所以把所有的长度加和就可以了
如果存在奇数度的点只可能是一个起点一个终点,把所有的距离加和然后加一次从起点到终点的最短路径就可以了。floyd算法,
1 #include <algorithm> 2 #include <iostream> 3 #include <string> 4 using namespace std; 5 //主函数 6 int main(void) { 7 //aMat为连通路口的邻接矩阵,aIdHash为路口字母与其编号的对应表 8 //nNodeCnt为路口数量,nRout为最小路径长度 9 int aMat[26][26], aIdHash[26], nNodeCnt = 0, nRout = 0, nInf = 0xFFFFFF; 10 fill(&aMat[0][0], &aMat[26][0], nInf); 11 fill(&aIdHash[0], &aIdHash[26], nInf); 12 //循环处理每一行输入,结束时将nRout清0 13 for (string strName; cin >> strName;) { 14 //如果街名为结束符,则按前一阶段的输入数据进行运算 15 if (strName == "deadend") { 16 //aOdd数组用于记录奇顶点,pOdd是aOdd的指针形式 17 int aOdd[2] = {0, 0}, *pOdd = &aOdd[0]; 18 for (int i = 0; i < nNodeCnt && pOdd != &aOdd[2]; ++i) { 19 //统计每一个顶点的相邻顶点数(连通路口数) 20 for (int j = 0; j < nNodeCnt; *pOdd += (aMat[i][j++] != nInf)); 21 //如果发现奇顶点,加入奇顶点数组 22 if (*pOdd % 2 != 0) { 23 *(pOdd++) = i; 24 } 25 } 26 //如果存在两个奇顶点,则开始Floyd算法,找最短路径 27 if (pOdd != aOdd) { 28 for (int k = 0, nSum; k < nNodeCnt; ++k) { 29 for (int i = 0; i < nNodeCnt; ++i) { 30 //为加快运算减少代码,设置临时变量p = aMat[i] 31 for (int j = 0, *p = &aMat[i][0]; j < nNodeCnt; ++j) { 32 nSum = p[k] + aMat[k][j]; 33 p[j] = nSum < p[j] ? nSum : p[j]; 34 } 35 } 36 } 37 nRout += aMat[aOdd[0]][aOdd[1]]; 38 } 39 //输出最小路径长度 40 cout << nRout << endl; 41 //初始化数据,以便进行下一轮计算 42 fill(&aMat[0][0], &aMat[nNodeCnt][0], nInf); 43 fill(&aIdHash[0], &aIdHash[26], nInf); 44 nRout = nNodeCnt = 0; 45 continue; 46 } 47 //街道名称的首尾字母 48 int nF = *strName.begin() - 'a', nL = *(strName.end() - 1) - 'a'; 49 //验证路口字母是否已经存在,否则添加路口 50 nF = (aIdHash[nF] = aIdHash[nF] == nInf ? nNodeCnt++ : aIdHash[nF]); 51 nL = (aIdHash[nL] = aIdHash[nL] == nInf ? nNodeCnt++ : aIdHash[nL]); 52 //在邻接距阵中添加路口节点 53 aMat[nF][nL] = aMat[nL][nF] = strName.length(); 54 //统计路径长度 55 nRout += strName.length(); 56 } 57 return 0; 58 }
uva,534
青蛙从一块石头跳到另外一块石头,文最小生成树里面的最大距离
Kruskal
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 using namespace std; 7 const int N=202; 8 9 struct Point{ 10 int x,y; 11 void read() 12 { 13 scanf("%d%d",&x,&y); 14 } 15 }p[N]; 16 17 double dis(Point a,Point b) 18 { 19 int dx=a.x-b.x; 20 int dy=a.y-b.y; 21 22 return sqrt(dx*dx+dy*dy); 23 } 24 25 26 struct Edge 27 { 28 int u; 29 int v; 30 double d; 31 32 Edge(){} 33 Edge(int u,int v) 34 { 35 this->u=u; 36 this->v=v; 37 d=dis(p[u],p[v]); 38 } 39 bool operator<(const Edge& c)const 40 { 41 return d<c.d; 42 } 43 }E[N*N]; 44 45 int n,parent[N]; 46 47 int find(int x) 48 { 49 return x==parent[x] ? x:parent[x]=find(parent[x]); 50 } 51 52 53 int main() 54 { 55 int cas=1; 56 while(~scanf("%d",&n),n) 57 { 58 int en=0; 59 60 for(int i=0;i<n;i++) 61 { 62 parent[i]=i; 63 p[i].read(); 64 for(int j=0;j<i;j++) 65 { 66 E[en++]=Edge(i,j); 67 } 68 } 69 70 sort(E,E+en); 71 for(int i=0;i<en;i++) 72 { 73 int pa=find(E[i].u); 74 int pb=find(E[i].v); 75 76 if(pa!=pb) 77 parent[pa]=pb; 78 79 if(find(0)==find(1)) 80 { 81 printf("Scenario #%d\nFrog Distance = %.3lf\n\n",cas++,E[i].d); 82 break; 83 } 84 } 85 } 86 return 0; 87 }
Dijkstra
1 #include <cstdio> 2 #include <cmath> 3 4 using namespace std; 5 6 double min(double a,double b) 7 { 8 return (a<b)?a:b; 9 } 10 11 double dis(double ax,double ay,double bx,double by) 12 { 13 return sqrt((ax-bx)*(ax-bx)+(ay-by)*(ay-by)); 14 } 15 16 int main() 17 { 18 int n; 19 int sets=1; 20 21 while(~scanf("%d",&n),n) 22 { 23 int i; 24 double stone[205][5]={0}; 25 26 for(i=0;i<n;i++) 27 scanf("%lf%lf",&stone[i][0],&stone[i][1]); 28 29 int now=0; 30 31 double dijkstra[205][5]={0}; 32 for(i=0;i<205;i++) 33 dijkstra[i][0]=2147483647; 34 dijkstra[0][1]=1; 35 36 double maxdistance=0; 37 38 int temp=1; 39 while(now!=1) 40 { 41 temp=1; 42 for(i=0;i<n;i++) 43 if(dijkstra[i][1]==0) 44 { 45 dijkstra[i][0]=min(dis(stone[now][0],stone[now][1],stone[i][0],stone[i][1]),dijkstra[i][0]); 46 if(dijkstra[i][0]<dijkstra[temp][0]) 47 temp=i; 48 } 49 now=temp; 50 maxdistance=(dijkstra[now][0]>maxdistance?dijkstra[now][0]:maxdistance); 51 dijkstra[now][1]=1; 52 } 53 printf("Scenario #%d\n",sets++); 54 printf("Frog Distance = %.3lf\n\n",maxdistance); 55 } 56 return 0; 57 }
uva,10000
换一下思路,给每个问题的权值为-1求最小的绝对值最大注意最后换行。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 using namespace std; 7 8 const int maxn=105; 9 int map[maxn][maxn]; 10 int path[maxn][maxn]; 11 int n; 12 13 14 void floyd() 15 { 16 17 for(int k=1;k<=n;k++) 18 for(int i=1;i<=n;i++) 19 for(int j=1;j<=n;j++) 20 { 21 map[i][j]=min(map[i][j],map[i][k]+map[k][j]); 22 } 23 24 } 25 26 int main() 27 { 28 int start; 29 int from,to; 30 int cas=1; 31 while(~scanf("%d",&n),n) 32 { 33 memset(map,0x3F,sizeof(map)); 34 for(int i=1;i<=n;i++) 35 map[i][i]=0; 36 scanf("%d",&start); 37 while(true) 38 { 39 scanf("%d%d",&from,&to); 40 if(!from && !to) 41 break; 42 map[from][to]=-1; 43 } 44 floyd(); 45 46 int max=0; 47 int index=0; 48 for(int i=1;i<=n;i++) 49 { 50 if(map[start][i]<max) 51 { 52 max=map[start][i]; 53 index=i; 54 } 55 } 56 max=abs(max); 57 printf("Case %d: The longest path from %d has length %d, finishing at %d.\n\n",cas++,start,max,index); 58 } 59 return 0; 60 }
uva,10099
给一个强联通图,每条线路上有一个门限值,求运一拨人,最少运几次,
思想:用kruskal的思想求出最大生产树,然后求出树里面最小值的边,最后求解。
注意“”“”“”“”“ 导游要剔除。 即每次运的人要减一。。。。难怪一开始看不懂
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn=105; 8 9 struct Edge 10 { 11 int u,v; 12 int weight; 13 bool operator<(const Edge& a)const 14 { 15 return weight>a.weight; 16 } 17 }E[maxn*maxn]; 18 19 20 int parent[maxn]; 21 int find(int x) 22 { 23 return x==parent[x]?x:parent[x]=find(parent[x]); 24 } 25 26 int main() 27 { 28 int N,R; 29 int S,D,T; 30 int cas=1; 31 while(scanf("%d%d",&N,&R) && N+R) 32 { 33 for(int i=1;i<=N;i++) 34 parent[i]=i; //一开始赋值赋错了,tle了几次。 35 for(int i=0;i<R;i++) 36 { 37 scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].weight); 38 } 39 40 scanf("%d%d%d",&S,&D,&T); 41 sort(E,E+R); 42 int re=0; 43 for(int i=0;i<R;i++) 44 { 45 int pa=find(E[i].u); 46 int pb=find(E[i].v); 47 48 if(pa!=pb) 49 parent[pa]=pb; 50 if(find(S)==find(D)) 51 { 52 re=E[i].weight; 53 break; 54 } 55 } 56 re--; 57 int flag=0; 58 if(T%re==0) 59 flag=1; 60 int t=T/re; 61 if(!flag) 62 t++; 63 64 printf("Scenario #%d\nMinimum Number of Trips = %d\n\n",cas++,t); 65 } 66 return 0; 67 }