现在的位置: 首页 > 综合 > 正文

ZOJ 1708||hdu 1035 Robot Motion (链式前向星,dfs)

2017年10月18日 ⁄ 综合 ⁄ 共 2496字 ⁄ 字号 评论关闭

              这题用链式前向星求解,太简单了。

             真正的几乎完美之作啊。

题目意思:

    跟着图走,N 表示向上走,S表示向下走,E表示向右走,W表示向左走。

    如果走出去了就,输出走的步数。

    如果成环了,就输出走到多少步时碰到了环,然后输出环走一圈要多少步。

 

   解题思路:  链式前向星, 下面还有dfs直接解法:

  链式前向星,是一种数据结构。是ssfz神牛Malash创造的,至今广为流传的链式前向星。堪称完美。

  用一个数组存边的终点,一个数组存每一条边的序号。  再用一个数组存起点的最后一条出边的序号,注意该序号用来从存边的序号的数组里索引该起点的所有出边的序号的。

  理解了这一点就好办了。

  我们将题目的每一步,看成是一条边。用链式前向星存起来,于是该边就有了一个属于自己的边序号。

  这个边序号,在这个题目当中,就可以看作是走的第几步。

  然后我们每走一步,就判断,这个点所代表的边有没有用链式前向星存过。如果存过那么就跳出循环。直接输出这条已存过的边的序号减一。循环要走的步数就是总共的边减去这个序号+1、

 如果都没存过。就直接输出总共有多少条边就行了。

 

  其实链式前向星的用处很大。适合点多的题。而点少的题的话,用二维数组就行了。

  链式前向星的速度很快的。推荐使用。 

   膜拜Malash神牛   orz.......

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1000
typedef struct
{
    int to,next,cap;
} E;
E edge[N*N];
int V[N];
int p[N];
int M;

void insert(int from,int to)
{
    edge[M].to=to;
    edge[M].cap=1;
    edge[M].next=V[from];
    V[from]=M++;
}
int main()
{
    int n,m,s,i,j;
    char str[N][N],c;
    while(scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        scanf("%d\n",&s);
        M=1;
        memset(V,-1,sizeof(V));
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=m ; j++)
            {
                scanf("%c",&str[i][j]);
            }
            getchar();
        }
        i=1;
        while(1)
        {
            c=str[i][s];
            if(V[i]==-1)
            {
            insert(i,s);
            }

            else
            {
                for(j=V[i]; j+1; j=edge[j].next)
                if(edge[j].to==s)
                {
                    break;
                }
                if(!(j+1))
                insert(i,s);
                else break;
            }
            switch(c)
            {
            case 'N':
                i-=1;
                break;
            case 'W':
                s-=1;
                break;
            case 'E':
                s+=1;
                break;
            case 'S':
                i+=1;
                break;
            }
            if(s>m||i>n||!i||!s)break;
        }
        if(!i||!s||i>n||s>m)
        printf("%d step(s) to exit\n",M-1);
        else
        {
            printf("%d step(s) before a loop of %d step(s)\n",j-1,M-j);
        }
    }

    return 0;
}

  

dfs:对每点进行标记即可,遇到标记过的,就拿当前dfs层数减去该标记,就是循环的步数,然后该标记就是循环钱走的步数

这代码是Zoj的,删掉n||m||k 的||k 提交hdu的即可。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>

using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define REP(a,b,c) for(int a = b; a < c; ++a)
#define eps 10e-8

const int MAX_ = 1010;
const int N = 100010;
const int INF = 0x7fffffff;

int C[MAX_];
char str[MAX_][MAX_];
int a[MAX_];
int vis[MAX_][MAX_];

int n, m, k, step, loop;

int dir[4][2] = {{0,-1},{-1,0},{0,1},{1,0}};

int selectf(char c)
{
    switch(c){
        case 'W':return 1;
        case 'S':return 2;
        case 'E': return 3;
        case 'N': return 0;
    }
}

void dfs(int x, int y, int f)
{
    if(vis[x][y] != -1){
        loop = f-vis[x][y] ;
        step = vis[x][y];
        return ;
    }

    int tmp = selectf(str[x][y]);
    int xx, yy;
    xx = x + dir[tmp][1];
    yy = y + dir[tmp][0];
    vis[x][y] = f;
    if(xx < 0 || xx >= n || yy < 0 || yy >= m){
        step = f+1;
        return ;
    }

    dfs(xx, yy, f+1);

}

int main()
{
    int T;

    while(~scanf("%d%d%d", &n, &m, &k), n||m||k){
        REP(i, 0, n){
            scanf("%s",str[i]);
        }
        mst(vis,-1);
        loop= -1;
        step = -1;
        dfs(0, k-1, 0);
        if(loop == -1){
            printf("%d step(s) to exit\n", step);
        }
        else {
            printf("%d step(s) before a loop of %d step(s)\n", step, loop);
        }

    }
	return 0;
}

抱歉!评论已关闭.