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

来源:互联网 发布:如何评价阿凡达 知乎 编辑:程序博客网 时间:2024/06/06 04:25
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 0x3f3f3f3fstruct 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 0x3f3f3f3fint 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 0x3f3f3f3fint 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 0x3f3f3f3fstruct 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 0
原创粉丝点击