zoukankan      html  css  js  c++  java
  • 九度OJ 1008

    题目描述:
    给你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;
    }

  • 相关阅读:
    Django和Angular.js模板标签冲突的解决方式
    ImageMagick 使用经验
    Getting Real内容浓缩
    RA layer request failed
    [硬件结构]硬件体系结构中的缓存的定性与定量分析案例
    hdu5373
    百度地图之标注一组地理坐标&lt;2&gt;
    【KMP】hdu1867(A + B for you again) 杭电java a题真坑
    hdu1034 简单模拟
    杂谈之WEB前端project师身价
  • 原文地址:https://www.cnblogs.com/AkQuan/p/2455767.html
Copyright © 2011-2022 走看看