关于图论中最短路径的五道题-ACM

ACM队内训练第六周的专题是图论中最短路径问题,今晚终于把五道题目都AC了,下面依次总结一下并奉上代码。

题目列表

对应poj题目
poj1125 Stockbroker Grapevine
poj3615 Cow Hurdles
poj1847 Tram
poj1502 MPI Maelstrom
poj1860 Currency Exchange

NO.1 poj1125 Stockbroker Grapevine

题目给定一个有向图,求解最短路径,要求输出作为源的顶点坐标以及该顶点到达某个顶点的最大权值。数据量100,使用Floyd算法,复杂度为n^3。无特殊处理。

/*最短路径算法-Floyd算法*/
#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;

#define maxn 0x3f3f3f3f
struct Graph{   //邻接矩阵表示法
    int arcs[105][105];
}g;

struct ShortPath{
    int a[105][105];
}path;

void floyd(int n){
    for(int i=0 ; i<n ; i++)    //初始化
        for(int j=0 ; j<n ; j++)
            path.a[i][j] = g.arcs[i][j];

    for(int k=0 ; k<n ; k++)
        for(int i=0 ; i<n ; i++)
            for(int j=0 ; j<n ; j++){
                if(path.a[i][k]>=maxn || path.a[k][j]>=maxn)
                    continue;
                if(path.a[i][j] > (path.a[i][k] + path.a[k][j]))
                    path.a[i][j] = path.a[i][k] + path.a[k][j];
            }
}


int main()
{
    //freopen("in.txt","r",stdin);
    int n;
    while(cin>>n && n!=0){
        int m,j;
        memset(g.arcs,maxn,sizeof(g.arcs));
        for(int i=0 ; i<n ; i++)
            g.arcs[i][i]=0;
        for(int i=0 ; i<n ; i++){
            cin>>m;
            while(m--){
                cin>>j;
                cin>>g.arcs[i][j-1];
            }
        }
        floyd(n);

        int shortpath=maxn,pathlen,point=0;

        for(int i=0 ; i<n ; i++){
            bool flag=true;
            pathlen=0;
            for(int j=0 ; j<n ; j++){
                if(path.a[i][j]>=maxn){
                    flag=false;
                    break;
                }
                pathlen += path.a[i][j];
            }

            if(!flag)
                continue;

            if(shortpath>pathlen){
                shortpath=pathlen;
                point=i;
            }

        }

        if(shortpath>=maxn)
            cout<<"disjoint"<<endl;
        else{
            cout<<point+1<<" ";
            sort(path.a[point],path.a[point]+n);
            cout<<path.a[point][n-1]<<endl;
        }
    }
    return 0;
}

NO.2 poj3615 Cow Hurdles

题目要求最短路径中任意两点的最大距离,采用Floyd算法,直接把二维数组用作邻接矩阵,WA了两次,原因是输入时需注意从一根柱子跳到另一根柱子是不可逆的,也就是说a[x][y]!=a[y][x]。

#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;

#define maxn 0x3f3f3f3f
int a[305][305];

void floyd(int n){
    for(int k=1 ; k<=n ; k++)
        for(int i=1 ; i<=n ; i++)
            for(int j=1 ; j<=n ; j++)
                a[i][j] = min(a[i][j],max(a[i][k],a[k][j]));

}

int main(){
    int n,m,t;
    while(scanf("%d%d%d",&n,&m,&t)!=EOF){
        int x,y,z;
    //    memset(a,maxn,sizeof(a));
        for(int i=1 ; i<=n ; i++)
            for(int j=1 ; j<=n ; j++)
                a[i][j]=maxn;
        while(m--){
            //cin>>x>>y;
            scanf("%d%d%d",&x,&y,&z);
            a[x][y]=z;
            //a[y][x]=a[x][y];错误,需留意
        }

        floyd(n);

        while(t--){
            scanf("%d%d",&x,&y);
            if(a[x][y]>=maxn)
                printf("-1\n");
            else
                printf("%d\n",a[x][y]);
        }

    }
    return 0;
}

NO.3 poj1847 Tram

题目意思是说有n个点,从A点到其他点,若可达且是该行输入的第一个点则权值为0,若可达且不是第一个点则权值为1,否则不可达。由于数据量不大,使用Floyd算法求解。

#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define maxn 0x3f3f3f3f

int point[105][105];
int n,a,b;

void floyd(){
    for(int q=1 ; q<=n ; q++)
        for(int i=1 ; i<=n ; i++)
            for(int j=1 ; j<=n ; j++){
                if(point[i][j]>(point[i][q]+point[q][j]))
                    point[i][j] = point[i][q]+point[q][j];
            }

}

int main(){
    while(~scanf("%d%d%d",&n,&a,&b)){
        int m,k;
        for(int i=1 ; i<=n ; i++){  //初始化
            for(int j=1 ; j<=n ; j++){
                if(i==j)
                    point[i][j]=0;
                else
                    point[i][j]=maxn;
            }
        }

        for(int i=1 ; i<=n ; i++){
            scanf("%d",&m);
            for(int j=0 ; j<m ; j++){
                scanf("%d",&k);
                if(j==0)
                    point[i][k]=0;
                else
                    point[i][k]=1;
            }
        }

        floyd();

        if(point[a][b]>=maxn)
            cout<<-1<<endl;
        else
            cout<<point[a][b]<<endl;
    }
    return 0;
}

NO.4 poj1502 MPI Maelstrom

无向图求最短路径,无特殊要求,直接使用Dijkstra算法求解,复杂度为n^2。

/*Dijkstra算法-最短路*/
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define max 0x3f3f3f3f
struct Graph{   //邻接矩阵表示法
    int arcs[105][105];
}g;
int dist[105];  //储存最短路径

void init(Graph pg,int dist[],int n){
    dist[0] = 0;
    pg.arcs[0][0] = 1; //若对角线元素为1,则表示该顶点已被使用
    for(int i=1 ; i<n ; i++)
        dist[i] = pg.arcs[0][i];
}

void dijkstra(Graph g,int dist[],int n){
    int mv,minw;
    init(g,dist,n); //初始化

    for(int i=1 ; i<n ; i++){
        minw=max;
        mv=0;
        for(int j=1 ; j<n ; j++)    //选出距离v0最近的顶点
            if(g.arcs[j][j]==0 && dist[j]<minw){
                mv=j;
                minw=dist[j];
            }

        if(mv == 0) break; //v0与vi不连通,结束
        g.arcs[mv][mv] = 1;

        for(int j=1 ; j<n ; j++){
            if(g.arcs[j][j]==0 && dist[j] >dist[mv]+g.arcs[mv][j]){
                dist[j] = dist[mv]+g.arcs[mv][j];
            }
        }
    }
}

int main(){
    int n;
    while(cin>>n){
        memset(g.arcs,0,sizeof(g.arcs));
        string input;
        for(int i=1 ; i<n ; i++){
            for(int j=0 ; j<i ; j++){
                cin>>input;
                if(input=="x"){
                    g.arcs[i][j]=max;
                    g.arcs[j][i]=max;
                }else{
                    g.arcs[i][j]=atoi(input.c_str());
                    g.arcs[j][i]=atoi(input.c_str());
                }
            }
        }
        dijkstra(g,dist,n);
        sort(dist,dist+n);
        cout<<dist[n-1]<<endl;

    }
    return 0;
}

NO.5 poj1860 Currency Exchange

Bellman_Ford算法求解有向带权图是否存在正负环。数组开小导致RE,遍历的时候注意起点,输入的变量较多,顺序容易搞错。

#include <iostream>
#include<cstring>
#include<stdio.h>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;

struct Edge{
    int u,v;
    double rate,cost;
};

Edge edge[1005];
double dist[5005];
double ss;
int start,count1;

bool Bellman_Ford(int n){
    memset(dist,0,sizeof(dist));
    dist[start]=ss;
    bool flag;
    for(int i=1 ; i<n ; i++){
        flag=false;
        for(int j=0 ; j<count1 ; j++)
            if(dist[edge[j].v] < (dist[edge[j].u]-edge[j].cost)*edge[j].rate){
                dist[edge[j].v] = (dist[edge[j].u]-edge[j].cost)*edge[j].rate;
                flag = true;
            }
            if(!flag)
                break;
    }

    for(int j=0 ; j<count1 ; j++)
        if(dist[edge[j].v] < (dist[edge[j].u]-edge[j].cost)*edge[j].rate)
            return true;
    return false;
}


int main(){

    int n,m;
    while(cin>>n>>m>>start>>ss){
        count1=0;
        int uu,vv;
        double p1,p2,p3,p4;
        while(m--){
            cin>>uu>>vv>>p1>>p2>>p3>>p4;
            edge[count1].u=uu;
            edge[count1].v=vv;
            edge[count1].rate=p1;
            edge[count1].cost=p2;
            count1++;
            edge[count1].u=vv;
            edge[count1].v=uu;
            edge[count1].rate=p3;
            edge[count1].cost=p4;
            count1++;
        }

        if(Bellman_Ford(n))
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

结语

图论的题目接触不多,一开始写的代码有些赘余,后来发现后慢慢改正一些。感受最深的一处是:数据量不大的情况下,直接用二维数组表示图的邻接矩阵比较方便。以后做ACM题要有快速建模的意识!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值