- 题目描述:
-
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
- 输入:
-
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
- 输出:
-
输出 一行有两个数, 最短距离及其花费。
- 样例输入:
-
3 2 1 2 5 6 2 3 4 5 1 3 0 0
- 样例输出:
-
9 11
样例太水,自己弄了组数据:View Code
input: 6 8 2 3 4 10 3 4 1 10 2 1 1 7 1 6 2 3 1 5 10 3 5 4 2 3 6 5 2 2 3 5 5 7 1 4 3 2 1 2 5 6 2 3 4 5 1 3 0 0 output: 6 8 9 11
代码:
方法1:邻接表+Dijkstra+STL+优先队列【这个是我写的,后面的都是其他网友提供的,十分感谢】
View Code
#include <stdio.h> #include <string.h> #include <malloc.h>// #include <algorithm> #include <queue> #include <functional> #include <utility> #include <vector> using namespace std; #define INF (1<<30) #define MAXM 100002 #define MAXN 1002 typedef struct Tab{ int eid; struct Tab *next; Tab()://构造函数 eid(-1),next(NULL){} }tab; int u[MAXM], v[MAXM], d[MAXM], p[MAXM]; int n, m; int s, t; typedef pair<int,int> pii; priority_queue<pii, vector<pii>, greater<pii> > PQ; bool vis[MAXN]; int dis[MAXN]; int val[MAXN]; int main() { //freopen("jdoj1008.in", "r", stdin); while(scanf("%d%d", &n, &m), n&&m) { tab first[MAXN];//构造函数已经初始化了,不需要再次初始化 //read_graph for(int e=1; e<=m; e++) { scanf("%d%d%d%d", &u[e], &v[e], &d[e], &p[e]); tab *q; q = (tab*)malloc(sizeof(tab)); q->eid = e; q->next = first[u[e]].next; first[u[e]].next = q; q = (tab*)malloc(sizeof(tab)); q->eid = e; q->next = first[v[e]].next; first[v[e]].next = q; } scanf("%d%d", &s, &t);//起始地点和终止地点 memset(vis, 0, sizeof vis); for(int i=1; i<=n; i++){ dis[i] = (i==s ? 0 : INF); val[i] = (i==s ? 0 : INF); } PQ.push(make_pair(dis[s], s)); //起点进入优先队列 while(!PQ.empty()) {//Dijkstra pii tu = PQ.top(); PQ.pop(); int x = tu.second; if(vis[x]) continue;//已经算过,忽略 vis[x] = true; //标记算过 for(tab *eq=first[x].next; eq!=NULL; eq=eq->next) { int e = eq->eid; int ve = (v[e]!=x ? v[e] : u[e]); //printf("%d %d -- %d %d*\n", ve, u[e], v[e], x); if(dis[ve] > dis[x]+d[e]) { dis[ve] = dis[x] + d[e];//更新距离 val[ve] = val[x] + p[e];//更新费用 PQ.push(make_pair(d[ve], ve));//加入优先队列 } else if(dis[ve] == dis[x]+d[e])//距离相等的情况下,选费用小的 { if(val[ve] > val[x] + p[e]) { val[ve] = val[x] + p[e];//更新费用 PQ.push(make_pair(d[ve], ve));//加入优先队列 } } } } printf("%d %d\n", dis[t], val[t]); /*for(int i=1; i<=n; i++) { tab *q; q = first[i].next; printf("%d : ", i); while(q!=NULL){ printf(" --> %d", q->eid); q = q->next; } printf("\n"); } */ }//while(1); return 0; }
方法2:递归深度优先遍历+排序
View Code
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; typedef struct node { int d; int cost; };//c[]的结点类型 int a[1001][1001], b[1001][1001]; //a[]是距离阵, b[]是花费阵 int visited[1001]; int n, m, s, t, ctop; node c[100000];//最终代排序数组 bool cmp(node x, node y) { if(x.d != y.d)return x.d < y.d; else return x.cost < y.cost; } int getfirstneighbor(int s) //找第一个邻居 { for(int i = 1; i <= n; i++) if(a[s][i] != -1)return i; return -1; } int getnextneighbor(int s, int w) //找下一个邻居 { for(int i = w + 1; i <= n; i++) if(a[s][i] != -1)return i; return -1; } void compute(int s, int e, int d, int cost) //基于邻接矩阵的DFS { int w; if(s == e) { c[ctop].d = d; c[ctop].cost = cost; ctop++; } else { visited[s] = 1; w = getfirstneighbor(s); while(w != -1) { if(visited[w] == 0) { compute(w, e, d + a[s][w], cost + b[s][w]); } w = getnextneighbor(s, w); } visited[s] = 0; //反复通过该点 } } int main(void) { int head, tail; int d, p; while(scanf("%d%d", &n, &m) != EOF) { if(n == 0 && m == 0)break; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) a[i][j] = b[i][j] = -1; visited[i] = 0; } for(int i = 0; i < m; i++) { scanf("%d%d%d%d", &head, &tail, &d, &p); a[head][tail] = a[tail][head] = d; b[head][tail] = b[tail][head] = p; } scanf("%d%d", &s, &t); ctop = 0; compute(s, t, 0, 0); sort(c, c + ctop, cmp); printf("%d %d\n", c[0].d, c[0].cost); } return 0; }
其他AC代码:邻接矩阵+DFS(这也AC了...)
View Code
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; typedef struct node{ int d; int cost; };//c[]的结点类型 int a[1001][1001],b[1001][1001];//a[]是距离阵, b[]是花费阵 int visited[1001]; int n,m,s,t,ctop; node c[100000];//最终代排序数组 bool cmp(node x,node y){ if(x.d!=y.d)return x.d<y.d; else return x.cost<y.cost; } int getfirstneighbor(int s){//找第一个邻居 for(int i=1;i<=n;i++) if(a[s][i]!=-1)return i; return -1; } int getnextneighbor(int s,int w){//找下一个邻居 for(int i=w+1;i<=n;i++) if(a[s][i]!=-1)return i; return -1; } void compute(int s,int e,int d,int cost){//基于邻接矩阵的DFS int w; if(s==e){ c[ctop].d=d; c[ctop].cost=cost; ctop++; } else{ visited[s]=1; w=getfirstneighbor(s); while(w!=-1){ if(visited[w]==0){ compute(w,e,d+a[s][w],cost+b[s][w]); } w=getnextneighbor(s,w); } visited[s]=0;//反复通过该点 } } int main(void){ int head,tail; int d,p; while(scanf("%d%d",&n,&m)!=EOF){ if(n==0&&m==0)break; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) a[i][j]=b[i][j]=-1; visited[i]=0; } for(int i=0;i<m;i++){ scanf("%d%d%d%d",&head,&tail,&d,&p); a[head][tail]=a[tail][head]=d; b[head][tail]=b[tail][head]=p; } scanf("%d%d",&s,&t); ctop=0; compute(s,t,0,0); sort(c,c+ctop,cmp); printf("%d %d\n",c[0].d,c[0].cost); } return 0; }
邻接表+Dijkstra
View Code
//邻接表+dijk算法 #include <iostream> #include <cstdio> #include <cstring> using namespace std; #define inf 10000000 const int Maxn = 200005; int N,M; struct Edge{ int v,next; int dt,ct; }edge[Maxn];//边数 int first[1005]; int r,s,t; int vis[1005]; struct BNode{ int dist,cost; }P[1005]; //节点信息 //相当于链表的头插发,很有意思。比用邻接矩阵高效多了 void addedge(int u, int v, int d, int p) { edge[r].next = first[u]; edge[r].v = v; edge[r].dt = d; edge[r].ct = p; first[u] = r; r++; } int findminode()//在那么多节点中找最小的 { int i,Maxn = inf; int index = 0; for(i = 1; i<=N; i++) if(P[i].dist<Maxn && !vis[i]) { Maxn = P[i].dist; index = i; } //注意,如果存在多个相同的最短路径,要返回最小花费的节点 if(index) { for(i = 1; i<=N; i++) if(P[i].cost<P[index].cost && !vis[i])index = i; } return index; } void solve() { int i; for(i = 1; i<=N; i++) P[i].dist = P[i].cost = inf; P[s].dist = P[s].cost = 0; memset(vis,0,sizeof(vis)); int index = 1; while(index<N)//更新N-1次就够了 { int x = findminode(); if(!x)break; vis[x] = 1; index++; for(i = first[x]; i!=-1; i = edge[i].next) { int v = edge[i].v; if(P[x].dist+edge[i].dt<P[v].dist && !vis[v])//更新节点 { P[v].dist = P[x].dist+edge[i].dt; P[v].cost = P[x].cost+edge[i].ct; } else if(P[x].dist+edge[i].dt == P[v].dist && !vis[v])//如果存在多条最短路径,更新最小花费节点 { if(P[x].cost+edge[i].ct<P[v].cost)P[v].cost = P[x].cost+edge[i].ct; } } } cout<<P[t].dist<<' '<<P[t].cost<<endl; } int main() { int i,u,v,d,p; while(scanf("%d%d",&N,&M)!=EOF) { if(N == 0 && M == 0)break; memset(first,-1,sizeof(first)); r = 0; for(i = 0; i<M; i++) { scanf("%d%d%d%d",&u,&v,&d,&p); addedge(u,v,d,p); addedge(v,u,d,p); } scanf("%d%d",&s,&t); solve(); } return 0; }