zoukankan      html  css  js  c++  java
  • 最短路练习

    目录

    最短路练习

    poj 2387 Til the Cows Come Home

    poj 2253 Frogger 

    poj 1797 Heavy Transportation

    poj 3268 Silver Cow Party

    poj 1860 Currency Exchange

    hdu 3790 最短路径问题

    poj 2387 Til the Cows Come Home

    题意:求起点到终点的最短距离。

    bellman_ford算法:需要考虑重边。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int Max = 2e3+10;
    const int INF = 0x3f3f3f3f;
    typedef struct node{
        int to,from,ed;
    }Node;
    Node no[Max];
    int V,E;
    int d[Max];
    
    void bellman_ford(int s)
    {
       memset(d,0x3f,sizeof(d));
        d[s]=0;
        while(true)
        {
            bool update = false;
            for(int i=0;i<E;i++)
            {
                node e = no[i];
                 if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.ed){
                    d[e.to]=d[e.from]+e.ed;
                    update = true;
                }
                  if(d[e.to]!=INF&&d[e.from]>d[e.to]+e.ed){
                    d[e.from]=d[e.to]+e.ed;
                    update = true;
                }
            }
            if(!update) break;
        }
    }
    int main()
    {
        //freopen("input.txt","r",stdin);
        cin>>E>>V;
        for(int i=0;i<E;i++)
            cin>>no[i].from>>no[i].to>>no[i].ed;
    
        bellman_ford(1);
        cout<<d[V]<<endl;
        return 0;
    }

    poj 2253 Frogger 

    题意:起点到终点所有路径中最大跳跃距离的最小值
    核心在floyd 的变换方程:mp[i][j]=min(mp[i][j],max(mp[i][k],mp[k][j]));

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    double mp[210][210];
    double cal(int x1,int y1,int x2,int y2)
    {
      return sqrt(double(x1-x2)*(x1-x2)+double(y1-y2)*(y1-y2));
    }
    void floyd(int n)
    {
        for(int k=0;k<n;k++)
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                    //起点到终点所有路径中最大跳跃距离的最小值
                    mp[i][j]=min(mp[i][j],max(mp[i][k],mp[k][j]));
    
    }
    int main()
    {
        int n,x[210],y[210];
        int Case=1;
       // freopen("input.txt","r",stdin);
        while(cin>>n&&n)
        {
            memset(mp,0,sizeof(mp));
            for(int i=0;i<n;i++)
                cin>>x[i]>>y[i];
            for(int i=0;i<n;i++){
                for(int j=i+1;j<n;j++){
                    mp[i][j]=mp[j][i]=cal(x[i],y[i],x[j],y[j]);
                }
            }
            floyd(n);
            printf("Scenario #%d
    Frog Distance = %.3lf
    ",Case++,mp[0][1]);
            printf("
    ");
        }
        return 0;
    }
    
    void Dijkstra(int n)
    {
        memset(vis,0,sizeof(vis));
       for(int i=1;i<=n;i++)   dis[i]=INF;
        dis[1]=0;
        for(int i=1;i<=n;i++)
        {
            int minn = INF ,k;
            for(int j=1;j<=n;j++)
            {
                if(vis[j]==0 && dis[j]<minn){
                    k = j;
                    minn = dis[j];
                }
            }
            vis[k]=1;
            for(int j=1;j<=n;j++)
                dis[j]=min(dis[j],max(dis[k],mp[k][j]));
        }
    }

    poj 1797 Heavy Transportation

    题意:n条公路,要把物品从公路1运送到公路n 每条路都有其最大承载量 要求将物品从1运到N的过程,一次所能运的最多的货物

    即:求从顶点1到顶点n的  所有可行路径中  各边权值的最小值的最大值

    poj 2253类似,但这道题用floyd会T

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int Max = 1e3+10;
    
    int mp[Max][Max];
    int vis[Max],dis[Max];
    
    void Dijkstra(int n,int m)
    {
        for(int i=1;i<=n;i++)
        {
            dis[i]=mp[1][i];
            vis[i]=0;
        }
        int Max,v;
        for(int i=1;i<=n;i++)
        {
            Max = -1;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j] && dis[j]>Max)
                {
                    Max=dis[j];
                    v = j;
                }
            }
            vis[v] = 1;
    
            for(int j=1;j<=n;j++)
            {
                if(!vis[j]&&dis[j]<min(dis[v],mp[v][j] ) )
                    dis[j] = min(dis[v],mp[v][j]);
            }
        }
    }
    int main()
    {
        int T;
        int n,m,x,y,z;
        int Case = 1;
      //  freopen("input.txt","r",stdin);
        cin>>T;
        while(T--)
        {
            cin>>n>>m;
            memset(mp,0,sizeof(mp));
            for(int i=0;i<m;i++)
             {
                cin>>x>>y>>z;
                mp[x][y]=mp[y][x]=z;
             }
             Dijkstra(n,m);
             printf("Scenario #%d:
    ",Case++);
             cout<<dis[n]<<endl;
             cout<<endl;
        }
        return 0;
    }

    注意:求最大当中的最小(poj2253),和求最小当中的最大(poj1797),dis的初始值不一样。

    poj 3268 Silver Cow Party

    题意:有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。

    每头牛返回的最短时间很简单就可以算出来,这相当于从目标牛为起点求单源最短路径。但每头牛出发到目标牛的最短时间无法直接算出来,稍微转换一下,发现这个最短时间其实可以通过把所有的边取反向,然后再从目标牛求一次单源最短路径得到。得到这两个最短路径之后,取它们的和的最大者即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int Max = 1e3+10;
    int N,M,X;
    int cost[Max][Max];
    int vis[Max],dis[Max],bdis[Max];
    void Dijkstra()
    {
        for(int i=1;i<=N;i++)
        {
            vis[i]=0;
            dis[i]=cost[X][i];
            bdis[i]=cost[i][X];
        }
        for(int i=1;i<=N;i++)
        {
            int mi=INF,v;
            for(int j=1;j<=N;j++)
            {
                if(!vis[j]&&dis[j]<mi){
                    mi=dis[j];
                    v = j;
                }
            }
            vis[v]=1;
            for(int j=1;j<=N;j++)
            {
                if(vis[j]==0)
                    dis[j]=min(dis[j],dis[v]+cost[v][j]);
            }
        }
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=N;i++)
        {
            int mi=INF,v;
            for(int j=1;j<=N;j++)
            {
                if(!vis[j]&&bdis[j]<mi){
                    mi=bdis[j];
                    v = j;
                }
            }
            vis[v]=1;
            for(int j=1;j<=N;j++)
            {
                if(vis[j]==0)
                    bdis[j]=min(bdis[j],bdis[v]+cost[j][v]);
               //注意这个地方,现在是反着走,cost不要写成cost[v][j]了,这里WA了一下午
            }
        }
        int ma = -1;
        for(int i=1;i<=N;i++)
        {
            if(dis[i]+bdis[i]>ma)
                ma = dis[i]+bdis[i];
        }
        cout<<ma<<endl;
    }
    int main()
    {
        int from,to;
        cin>>N>>M>>X;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                if(i==j) cost[i][j]=0;
                else
                    cost[i][j]=INF;
        for(int i=1;i<=M;i++)
        {
            cin>>from>>to;
            cin>>cost[from][to];
        }
        Dijkstra();
    
        return 0;
    }

    poj 1860 Currency Exchange

    题意:输入n,m,s,v分别代表:有n种货币,有m个地方可以进行货币交换,      你起始的货币种类,你起始货币种类的数目      循环m次接下来输入a,b,rab,cab,rba,cba分别代表a——>b交换      rab:把a换成b的汇率,cab:a换成b的手续费;      问经过重复的交换是否可以使初始货币的总量增加

    分析:一种货币就是一个点一个“兑换点”就是图上两种货币之间的一个      兑换方式,是双边,但A到B的汇率和手续费可能与B到A的汇率和手续费不同。      唯一值得注意的是权值,当拥有货币A的数量为V时,A到A的权值为K,即没有兑换      而A到B的权值为(V-Cab)*Rab本题是“求最大路径”,之所以被归类为“求最小路径”      是因为本题题恰恰与bellman-Ford算法的松弛条件相反,求的是能无限松弛的最大正      权路径,但是依然能够利用bellman-Ford的思想去解题。      因此初始化dis(S)=V   而源点到其他点的距离(权值)初始化为无穷小(0),      当s到其他某点的距离能不断变大时,说明存在最大路径;如果可以一直变大,      说明存在正环。判断是否存在环路

    注意:要两次使用floyd。第一次用,是本金经过其他总换点的兑换,其他币的价值,并且存下来;

    第二次用floyd算法,是为了,和第一个用,作比较,看看其他币种的价值是否增加,如果是,那么判断是正权回路;这么做的目的,判断正权回路,不单单是经过源点的正权回路,还有其他币种的正权回路;

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    const int Max = 105;
    
    int n,m,s;
    double mp[Max],C[Max][Max],R[Max][Max],v;
    //mp[]存的是权值 (mp[]-Cab)*Rab
    int floyd()
    {
        double dis[Max];
        for(int i=1;i<=n;i++) dis[i] = mp[i];
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if((mp[i]-C[i][j])*R[i][j] > mp[j])
                        mp[j]=(mp[i]-C[i][j])*R[i][j];
    
        for(int i=1;i<=n;i++)//判断有无正环
            if(dis[i]<mp[i])
                return 1;
            return 0;
    }
    int main()
    {
        int a,b;
        double c,d,e,f;
        cin>>n>>m>>s>>v;
        memset(mp,0,sizeof(mp));
        memset(R,0,sizeof(R));
        memset(C,0,sizeof(C));
        for(int i=1;i<=m;i++)
        {
            cin>>a>>b>>c>>d>>e>>f;
            R[a][b]=c;C[a][b]=d;
            R[b][a]= e;C[b][a]=f;
        }
        mp[s]=v;
        floyd();
        if(floyd()) printf("YES
    ");
        else printf("NO
    ");
        return 0;
    }
    

    hdu 3790 最短路径问题

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int Max = 1e3+10;
    const int INF = 0x3f3f3f3f;
    int V,E;
    struct node{
        int from,to,ed,cost;
    };
    node no[100010];
    int dis[Max],spent[Max];
    void bellman(int s)
    {
        memset(dis,0x3f,sizeof(dis));
        memset(spent,0,sizeof(spent));
        dis[s]=0;
        while(true)
        {
            bool update = false;
            for(int i=0;i<E;i++)
            {
                node e = no[i];
                if(dis[e.to]>dis[e.from]+e.ed){
                    dis[e.to]=dis[e.from]+e.ed;
                    spent[e.to]=spent[e.from]+e.cost;
                    update = true;
    
                } else if((dis[e.to]==dis[e.from]+e.ed)&&(spent[e.to]>spent[e.from]+e.cost)){
                    spent[e.to]=spent[e.from]+e.cost;
                    update = true;
                }
    
                if(dis[e.from]>dis[e.to]+e.ed){
                    dis[e.from]=dis[e.to]+e.ed;
                    spent[e.from]=spent[e.to]+e.cost;
                    update = true;
                }else if((dis[e.from]==dis[e.to]+e.ed)&&(spent[e.from]>spent[e.to]+e.cost)){
                    spent[e.from]=spent[e.to]+e.cost;
                    update = true;
                }
            }
            if(!update) break;
        }
    }
    
    int main()
    {
        while(~scanf("%d%d",&V,&E)){
                if(V==0&&E==0) break;
            for(int i=0;i<E;i++)
               scanf("%d%d%d%d",&no[i].from,&no[i].to,&no[i].ed,&no[i].cost);
                int s,en;
                scanf("%d%d",&s,&en);
            bellman(s);
               printf("%d %d
    ",dis[en],spent[en]);
        }
        return 0;
    }
    
  • 相关阅读:
    python基础#1
    shell脚本基础练习题
    shell计算100以内加法
    shell脚本添加用户
    python学习ing
    框架
    前端
    python基础之数据类型-面向对象
    python四种列表的插入方法及其效率
    Charles高阶操作
  • 原文地址:https://www.cnblogs.com/qie-wei/p/10160147.html
Copyright © 2011-2022 走看看