简单的图论问题?

来源:互联网 发布:mysql最大连接数 编辑:程序博客网 时间:2024/05/17 04:04

1780: 简单的图论问题?

        Time Limit: 5 Sec     Memory Limit: 128 Mb     Submitted: 173     Solved: 30    

Description

给一个 行 列的迷宫,每个格子要么是障碍物要么是空地。每个空地里都有一个权值。你的 任务是从找一条(r1,c1)(r2,c2)的路径,使得经过的空地的权值之和最小。每一步可以往上下 左右四个方向之一移动一格,但不能斜着移动,也不能移动到迷宫外面或者进入障碍物格子。

如下图,灰色格子代表障碍物。路径 A->B->D->F->E 的权值为 10+3+6+14+8=41,它是从 到 的最优路径。注意,如果同一个格子被经过两次,则权值也要加两次。


为了让题目更有趣(顺便增加一下难度),你还需要回答另外一个问题:如果你每次必须转弯 (左转、右转或者后退,只要不是沿着上次的方向继续走即可),最小权值是多少?比如,在 上图中,如果你刚刚从 走到 B,那么下一步你可以走到 或者 A,但不能走到 G。在上图 中,到 的最优路径是 A->B->D->H->D->F->E,权和为 10+3+6+2+6+14+8=49。注意,经 过了两次。

Input

输入包含不超过 10 组数据。每组数据第一行包含 6 个整数 n, m, r1, c1, r2, c2 (2<=n,m<=500, 1<=r1,r2<=n, 1<=c1,c2<=m). 接下来的 n 行每行包含 m 个格子的描述。每个格子要么是一个 1~100 的整数,要么是星号"*"(表示障碍物)。起点和终点保证不是障碍物。

Output

对于每组数据,输出两个整数。第一个整数是“正常问题”的答案,第二个整数是“有趣问 题”的答案。如果每个问题的答案是“无解”,对应的答案应输出-1。

Sample Input

4 4 1 2 3 27 10 3 9
* 45 6 2
* 8 14 *
21 1 * * 2 4 1 1 1 41 2 3 49 * * 92 4 1 1 1 41 * 3 49 9 * 9 

Sample Output

Case 1: 41 49Case 2: 10 -1Case 3: -1 -1

Hint

Source

湖南省第十一届大学生计算机程序设计竞赛

心得: 不要遇到不会的题目,卡住了的题目就去网上找题解。不然比赛的时候遇到这样的问题会很慌,不知道该怎么下手。

这个题目我们拿那年胜赛的题目在打模拟赛。当时做出了第一问,那时候刚做了bfs 入门,还不会用优先队列,贼烦,这个题目没做出。看来要加强下bfs了。

算了看代码吧:

思路 :第一问还是比较简单,直接用优先队列 优先sum最小的状态出队列。当遇到了终点,那么他就是最短距离了;

第二问 :说是每次必须转弯,可以走相同的格子。那就是说。每一个格子有四种状态,用一个标志位来记录方向。

代码:

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<queue>using namespace std;#define INF 999999999struct node{    int x,y,sum;    int dir1;     friend bool operator < (node n1,node n2)    {        return n1.sum>n2.sum; //<为从大到小,>大于从小到大;    }};int map[501][501];int dis[501][501];int dir[4][2]={1,0,-1,0,0,1,0,-1};int turn[501][501][2];int vis[501][501];int vis1[501][501][4];int ans;int n,m,c1,c2,c3,c4;bool jude(int x,int y){    if(x<1||x>n||y<1||y>m)        return false;    return true;}void bfs(){    priority_queue<node>q;    node a={c1,c2,map[c1][c2],0};    q.push(a);    memset(vis,0,sizeof(vis));    vis[c1][c2]=1;    while(!q.empty())    {        node a=q.top();        q.pop();        if(a.x==c3&&a.y==c4)        {            ans=a.sum;            return ;        }        for(int i=0;i<4;i++)        {            int xx=a.x+dir[i][0];            int yy=a.y+dir[i][1];            if(!jude(xx,yy)) continue;            if(!vis[xx][yy]&&map[xx][yy]!=-1)            {                vis[xx][yy]=1;                node b={xx,yy,map[xx][yy]+a.sum,0};                q.push(b);            }        }    }    ans=-1;}void bfs2(){    priority_queue<node>q;    node aa={c1,c2,map[c1][c2],0};    node ab={c1,c2,map[c1][c2],1};    node ac={c1,c2,map[c1][c2],2};    node ad={c1,c2,map[c1][c2],3};    q.push(aa);     q.push(ab);      q.push(ac);       q.push(ad);//将第一个格子的状态都入队列。    memset(vis1,0,sizeof(vis1));   vis1[c1][c2][0]=vis1[c1][c2][1]=vis1[c1][c2][2]=vis1[c1][c2][3]=1;    while(!q.empty())    {        node a=q.top();        q.pop();        if(a.x==c3&&a.y==c4)        {            ans=a.sum;            return ;        }        for(int i=0;i<4;i++)        {  if(a.dir1==i) continue;            int xx=a.x+dir[i][0];            int yy=a.y+dir[i][1];            if(!jude(xx,yy)) continue;            if(!vis1[xx][yy][i]&&map[xx][yy]!=-1)            {                vis1[xx][yy][i]=1;                node b={xx,yy,map[xx][yy]+a.sum,i};                q.push(b);            }        }    }    ans=-1;}int main(){  int ii=1;    while(scanf("%d %d %d %d %d %d",&n,&m,&c1,&c2,&c3,&c4)!=EOF)    {        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)               {   char s[4];                   scanf("%s",s);                  // puts(s);                   if(s[0]=='*') map[i][j]=-1;                   else map[i][j]=atoi(s);               }        }         bfs();         printf("Case %d: ",ii++);       if(ans!=-1) printf("%d ",ans);       else printf("-1 ");        bfs2();         if(ans!=-1) printf("%d\n",ans);       else printf("-1\n");    }}


原创粉丝点击