九度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;
}

 


posted @ 2012-04-18 18:28  Muse牧马  Views(272)  Comments(0Edit  收藏  举报