• hdu 2425 Hiking Trip


    最短路径

    选拔赛的题目,当时一看就觉得做过类似的,马上写了个DP,怎么都WA,一直WA到结束。后来才想起来是个图论,求最短路

    题意:给一个矩阵,T表示树,.表示沙,#表示路,都是可以走的,而且他们各自带有一个值,vt,vs,vp,走到这个点要算上他们带的值,@表示石头不能走。再给你起点的行列和终点的行列(行列都是从0开始标记的),每次你都可以往上下左右四个方向走,重复走回同一个点也行,问你从起点走到终点的花费最少,(其中,起点带的那个值不用算上)

    首先读入原始的矩阵,把他们的值都记好,石头不能走,可以把它的值赋值为无穷,也可标记为-1,等下不需要用到它(代码中是标记为-1)

    然后按行从左到右给所有点标号,从1标到n*m。因为一个点可以走向它上下左右四个方向,其实就是和它四个方向的点相连,所以我们把这n*m个点变为一个图,目的就是求起点到终点的最短路。另外建图的时候,是建无向边,而且一个点最多和四个点相连,所以用邻接表效率会更高。另外无向边拆为有向边建图的时候i--->j,边权应该是j这个点所带的值

    写了两个代码,一个spfa求最短路,一个是dij的优先队列版

    spfa

    /*
    1.现将矩阵转换为图
    2.在图上运行最短路算法,用spfa或者优先队列优化(堆优化)的dij
    
    ‘T’, ‘.’, ‘#’, ‘@’
    tree, sand, path and stone. 
    
    VP, VS, VT
    path, sand, or tree
    */
    
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define N 25*25
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    struct edge
    {
        int u,v,w,next;
    }e[N*N];
    int nume , vp,vs,vt , row,col , r1,c1,r2,c2;
    int first[N],d[N],a[25][25];
    int xx[4]={-1,1,0,0} , yy[4]={0,0,-1,1};  //上下左右四个方向
    
    void spfa(int s ,int t)
    {
        queue<int>q;
        bool inq[N];
        memset(d,0x3f,sizeof(d));
        d[s]=0;
        memset(inq,0,sizeof(inq));
        inq[s]=1;
        q.push(s);
        while(!q.empty())
        {
            int u,v,w;
            u=q.front();
            q.pop();
            inq[u]=0;
            for(int k=first[u]; k!=-1; k=e[k].next)
            {
                v=e[k].v; w=e[k].w;
                if(d[u]+w < d[v]) //松弛
                {
                    d[v]=d[u]+w;
                    if(!inq[v]) 
                    { q.push(v); inq[v]=1; }
                }
            }
        }
        if(d[t]!=INF) printf("%d\n",d[t]);
        else          printf("-1\n");
    }
    
    void add(int u ,int v ,int w)
    {
        e[nume].u=u; e[nume].v=v; e[nume].w=w;
        e[nume].next=first[u]; first[u]=nume++;
    }
    
    void build()
    {
        int n1,n2,x,y;
        memset(first,-1,sizeof(first));
        nume=0;
        for(int i=1; i<=row; i++) //枚举列
            for(int j=1; j<=col; j++) //枚举行
                if(a[i][j]!=-1) //不是石头的才建边
                {
                    n1=(i-1)*col+j;  //当前点的标号
                    for(int k=0; k<4; k++) //枚举当前点的四个方向
                    {
                        x=i+xx[k]; y=j+yy[k];
                        if(a[x][y]!=-1) //不是石头可以建边
                        {
                            n2=(x-1)*col+y; 
                            add(n1,n2,a[x][y]);
                            //添加一条有向边,边权就是n2点的值
                        }
                    }
                }
    }
    
    void input()
    {
        for(int i=0; i<=col+1; i++) a[0][i]=a[row+1][i]=-1; //矩阵上下两行不可到达
        for(int i=0; i<=row+1; i++) a[i][0]=a[i][col+1]=-1; //矩阵左右两列不可到达
        
        scanf("%d%d%d",&vp,&vs,&vt);
        for(int i=1; i<=row; i++)
        {
            char tmp[25];
            scanf("%s",tmp+1);
            for(int j=1; j<=col; j++)
            {
                if(tmp[j]=='T') a[i][j]=vt;
                else if(tmp[j]=='.') a[i][j]=vs;
                else if(tmp[j]=='#') a[i][j]=vp;
                else a[i][j]=-1;
            }
        }
        scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
        ++r1; ++c1; ++r2; ++c2;
    }
    
    int main()
    {
        int Case=0;
        while(scanf("%d%d",&row,&col)!=EOF)
        {
            input(); //读入原始的矩阵
            build(); //将矩阵转化为图
            printf("Case %d: ",++Case);
            spfa((r1-1)*col+c1 , (r2-1)*col+c2);  //最短路算法计算源点到汇点的距离
        }
        return 0;
    }

    dij+优先队列

    /*
    1.现将矩阵转换为图
    2.在图上运行最短路算法,用spfa或者优先队列优化(堆优化)的dij
    
    ‘T’, ‘.’, ‘#’, ‘@’
    tree, sand, path and stone. 
    
    VP, VS, VT
    path, sand, or tree
    */
    
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <utility>
    #define N 25*25
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    typedef pair<int,int>pii;
    
    struct edge
    {
        int u,v,w,next;
    }e[N*N];
    int nume , vp,vs,vt , row,col , r1,c1,r2,c2;
    int first[N],d[N],a[25][25];
    int xx[4]={-1,1,0,0} , yy[4]={0,0,-1,1};  //上下左右四个方向
    
    void dij(int s, int t)
    {
        bool done[N];
        priority_queue<pii,vector<pii>,greater<pii> >q;
        memset(d,0x3f,sizeof(d));
        d[s]=0;
        memset(done,0,sizeof(done));
        q.push(make_pair(d[s],s));
        while(!q.empty())
        {
            pii tmp=q.top();
            q.pop();
            int u,v,w;
            u=tmp.second;
            if(done[u]) continue;
            done[u]=1;
            for(int k=first[u]; k!=-1; k=e[k].next)
            {
                v=e[k].v; w=e[k].w;
                if(d[u]+w < d[v])
                {
                    d[v]=d[u]+w;
                    q.push(make_pair(d[v],v));
                }
            }
        }
        if(d[t]!=INF) printf("%d\n",d[t]);
        else          printf("-1\n");
    }
    
    void add(int u ,int v ,int w)
    {
        e[nume].u=u; e[nume].v=v; e[nume].w=w;
        e[nume].next=first[u]; first[u]=nume++;
    }
    
    void build()
    {
        int n1,n2,x,y;
        memset(first,-1,sizeof(first));
        nume=0;
        for(int i=1; i<=row; i++) //枚举列
            for(int j=1; j<=col; j++) //枚举行
                if(a[i][j]!=-1) //不是石头的才建边
                {
                    n1=(i-1)*col+j;  //当前点的标号
                    for(int k=0; k<4; k++) //枚举当前点的四个方向
                    {
                        x=i+xx[k]; y=j+yy[k];
                        if(a[x][y]!=-1) //不是石头可以建边
                        {
                            n2=(x-1)*col+y; 
                            add(n1,n2,a[x][y]);
                            //添加一条有向边,边权就是n2点的值
                        }
                    }
                }
    }
    
    void input()
    {
        for(int i=0; i<=col+1; i++) a[0][i]=a[row+1][i]=-1; //矩阵上下两行不可到达
        for(int i=0; i<=row+1; i++) a[i][0]=a[i][col+1]=-1; //矩阵左右两列不可到达
        
        scanf("%d%d%d",&vp,&vs,&vt);
        for(int i=1; i<=row; i++)
        {
            char tmp[25];
            scanf("%s",tmp+1);
            for(int j=1; j<=col; j++)
            {
                if(tmp[j]=='T') a[i][j]=vt;
                else if(tmp[j]=='.') a[i][j]=vs;
                else if(tmp[j]=='#') a[i][j]=vp;
                else a[i][j]=-1;
            }
        }
        scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
        ++r1; ++c1; ++r2; ++c2;
    }
    
    int main()
    {
        int Case=0;
        while(scanf("%d%d",&row,&col)!=EOF)
        {
            input(); //读入原始的矩阵
            build(); //将矩阵转化为图
            printf("Case %d: ",++Case);
            dij((r1-1)*col+c1 , (r2-1)*col+c2);
        }
        return 0;
    }
  • 相关阅读:
    佛山Uber优步司机奖励政策(2月1日~2月7日)
    长沙Uber优步司机奖励政策(2月1日~2月7日)
    广州Uber优步司机奖励政策(2月1日~2月7日)
    西安Uber优步司机奖励政策(2月1日~2月7日)
    武汉Uber优步司机奖励政策(2月1日~2月7日)
    Apicloud自定义模块
    Android Studio导出jar包
    android studio 、 as 如何导入eclipse项目
    安卓 使用Gradle生成正式签名apk文件
    如何用Android studio生成正式签名的APK文件
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2951223.html
Copyright © 2020-2023  润新知