DFS练习

第二天,打卡;

目录

前言

A.Oil Deposits  POJ-1562

B.全排列   51Nod 2060

C.泉水   HRBUST 1143

D.Tempter of the Bone  HDU 1010

E.Prime Ring Problem   HDU 1016

F.马走日  OpenJ_Bailian - 4123 

G.ROADS  POJ - 1724 

H.N皇后问题  HDU 2553

总结


前言

dfs的基本概念和模板不在详细介绍,可以自行查阅博客学习

讲解详见 (21条消息) DFS(深度优先搜索算法)_无限迭代中......-CSDN博客_dfs深度优先搜索

模板详见(21条消息) BFS/DFS 模板 代码_Lemon_Chen-CSDN博客_bfs dfs 代码

dfs基本上是模板题,但其中的小细节值得注意

A.Oil Deposits  POJ-1562

模板题

AC代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

const int N=105;
int m,n;
char ch[N][N];
int vis[N][N];
int  vst[N][N];

bool check(int p,int q)
{
    if(p<0 || p>=n || q<0 || q>=m)
		return false;
	if(vst[p][q]==0)
		return true;
	return false;

}
void dfs(int x,int y)
{
    vst[x][y]=1;
      for(int dx=-1;dx<=1;dx++)
    {
		for(int dy=-1;dy<=1;dy++)
		{
			int nx=x+dx,ny=y+dy;
			if(check(nx,ny))
			{
				dfs(nx,ny);
			}
		}
    }

}
int main()
{
   while(scanf("%d %d",&n,&m)!=EOF){
		getchar();
		int ans=0;
		if(n==0&&m==0)	break;

		for(int i=0;i<n;i++)
        {
			for(int j=0;j<m;j++)
			{
				cin>>ch[i][j];
                if(ch[i][j]=='@')
                    vst[i][j]=0;
                else
                    vst[i][j]=1;
			}

		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(!vst[i][j])
				{
					dfs(i,j);
					ans++;
				}
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

B.全排列   51Nod 2060

最基础的一道dfs题

AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N=10;
int a[N];
int vis[10];
int n;

void print()
{
    for(int i=1;i<=n;i++)
        cout << a[i]  << " ";
    cout << endl;
}
void dfs(int x)
{
    if(x>n)
    {
        print();
        return;
    }

    for(int i=1;i<=n;++i)
    {
        if(!vis[i])
        {
            vis[i]=1;
            a[x]=i;
            dfs(x+1);
            vis[i]=0;

        }
    }
    return;
}

int main()
{
    cin >> n;
    dfs(1);
    return 0;
}

C.泉水   HRBUST 1143

需要注意水只能流向低处,所以流向的地方必须低于泉眼才能继续递归下去

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N=1005;
bool vis[N][N];
int high[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
int p1,p2,m,n;
int ans;

bool check(int x,int y)
{
    if(x>0&&x<=n&&y>0&&y<=m&&!vis[x][y]&&high[x][y]<=high[p1][p2])
        return true;
    else
        return false;
}

void dfs(int x,int y)
{
    ans++;
    vis[x][y]=1;
    for(int i=0;i<4;i++)
    {
        int nx=x+dir[i][0];
        int ny=y+dir[i][1];
        if(check(nx,ny))
            dfs(nx,ny);
    }
}

int main()
{
    while(scanf("%d %d %d %d",&n,&m,&p1,&p2)!=EOF)
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            cin >> high[i][j];

        ans=0;
        dfs(p1,p2);
        cout << ans << endl;

    }
    return 0;
}

D.Tempter of the Bone  HDU 1010

这题格外要注意剪枝的问题,如果不使用奇偶剪枝,就会超时。

dis=abs(x-p)+abs(y-q),从起点到终点的步数是确定的,所以可以剪枝

AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=10;
char ch[N][N];
int vis[N][N];
int vst[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
int t,n,m;
int flag=0;
int x,y,p,q;

void dfs(int x,int y,int cnt)
{
    if(flag==1)
        return;

    if(cnt==t&&x==p&&y==q)
    {
        flag=1;
        return;
    }

    for(int i=0;i<4;i++)
    {
        int nx=x+dir[i][0];
        int ny=y+dir[i][1];
        if(x>=0 && y>=0 && x<n && y<m && !vis[nx][ny] && cnt<=t &&!vst[nx][ny])
        {
            vis[nx][ny]=1;
            dfs(nx,ny,cnt+1);
            vis[nx][ny]=0;
        }
    }
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&t))
    {
        if(n==0)
            break;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
        {
            cin >> ch[i][j];
            if(ch[i][j]=='S')
            {
                x=i,y=j;
            }
            else if(ch[i][j]=='D')
            {
                p=i,q=j;
            }
            else if(ch[i][j]=='X')
                vst[i][j]=1;
            else
                vst[i][j]=0;
        }

        int dis=abs(x-p)+abs(y-q);//奇偶剪枝
		if((dis%2)!=(t%2))
        {
			printf("NO\n");
			continue;
		}

        memset(vis,0,sizeof(vis));
        flag=0;
        vis[x][y]=1;
        dfs(x,y,0);
        if(flag==1)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

E.Prime Ring Problem   HDU 1016

常规题

AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int N =25;
int vis[N],a[N],is_prime[N];
int n;
int prim(int n)
{
    if(n==1)
        return 0;
    for(int i=2;i<n;++i)
        if(n%i==0)
        return 0;
    return 1;
}
void dfs(int v)
{
    if(v==n)
    {
        if(!is_prime[a[v]+a[1]])
            return;
        for(int i=1;i<n;++i)
            printf("%d ",a[i]);
        printf("%d\n",a[n]);
    }
    for(int i=2;i<=n;++i)
    {
        if(!vis[i]&&is_prime[a[v]+i])
        {
            a[v+1]=i;
            vis[i]=1;
            dfs(v+1);
            vis[i]=0;
        }
    }
}
int main()
{
    int cnt=1;
    for(int i=1;i<=50;++i)
        is_prime[i]=prim(i);
    while(~scanf("%d",&n))
    {
        memset(vis,0,sizeof(vis));
        printf("Case %d:\n",cnt++);
        a[1]=1;
        dfs(1);
        printf("\n");

    }
    return 0;
}

F.马走日  OpenJ_Bailian - 4123 

模板题

AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=20;
int vis[N][N];
int dir[8][2] = {{1,2},{-1,2},{1,-2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
int ans=0,nm;
int n,m,x,y;

void dfs(int x,int y,int cnt)
{
    if(cnt==nm)
    {
        ans++;
        return;
    }
    else
    {
        for(int i=0;i<8;++i)
        {
            int nx=x+dir[i][0];
            int ny=y+dir[i][1];
            if(nx >= 0 && ny >= 0 && nx < n && ny < m && !vis[nx][ny])
            {
                vis[nx][ny]=1;
                dfs(nx,ny,cnt+1);
                vis[nx][ny]=0;
            }
        }
    }
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        cin >> n >> m >> x >> y;
        ans=0;
        nm=n*m;
        vis[x][y]=1;
        dfs(x,y,1);
        cout << ans << endl;
    }

    return 0;
}

G.ROADS  POJ - 1724 

这道题需要用图来存储数据,这里选用的是链式前向星的方式,让后再按照dfs的做法来做

具体链式前向星的讲解详见(21条消息) 链式前向星--最通俗易懂的讲解_sugarbliss-CSDN博客_链式前向星

AC代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int N=10000+5;
int h[N],ne[N],vis[N];
int minn,flag;
int k,n,r;

struct Edge
{
    int to,l,w;
} edge[10101];

void add_edge(int u, int v, int w,int l,int i)
{
    edge[i].to = v;
    edge[i].w = w;
    edge[i].l = l;
    ne[i]=h[u];
    h[u]=i;
}

void dfs(int x,int num,int sum)
{
    if(num>k)
        return;
    if(sum>minn)
        return ;
    if(x==n&&num<=k)
    {
        if(sum<minn)
        {
            flag=1;
            minn=sum;
        }
        return ;
    }
    for(int i=h[x];i!=-1;i=ne[i])
    {
        if(vis[edge[i].to]==0)
        {
            vis[edge[i].to]=1;
            dfs(edge[i].to,num+edge[i].w,sum+edge[i].l);
            vis[edge[i].to]=0;
        }
    }
}
int main()
{
    int s,d,l,t;
    while(~scanf("%d%d%d",&k,&n,&r))
    {
        memset(h,-1,sizeof(h));
        memset(ne,-1,sizeof(ne));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<r;i++)
        {
            scanf("%d%d%d%d",&s,&d,&l,&t);
            add_edge(s,d,t,l,i);
        }
        vis[1]=1;
        minn=0x3f3f3f3f;
        flag=0;
        dfs(1,0,0);
        if(flag==0)
            printf("-1\n");
        else
            printf("%d\n",minn);
    }
    return 0;
}

H.N皇后问题  HDU 2553

此题需要将数据储存起来打表,不然会超时

AC代码

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;


int a[50],b[50],c[50],d[50];
int ans = 0;


bool check(int x,int y)
{
    if(!a[x]&&!b[y]&&!c[x+y]&&!d[x-y])
        return true;
    else
        return false;
}


void bfs(int n,int x)
{
    if(x>n-1)
    {
        ans++;
        return;
    }
    for(int i=0;i<n;i++)
    {
        if(check(x+1,i))
        {
            a[x+1]=1,b[i]=1,c[x+i+1]=1,d[x-i+1]=1;

            bfs(n,x+1);
            a[x+1]=0,b[i]=0,c[x+i+1]=0,d[x-i+1]=0;

        }
    }
}

int main()
{
    int sum[15];
    int n;
    for(int i=1;i<=10;i++)
	{
		memset(a,0,sizeof(a));
		ans=0;
		bfs(i,0);
		sum[i]=ans;
	}
    while(cin >> n)
    {
        if(n==0)
            return 0;
    cout << sum[n] << endl;
    }
    return 0;
}

总结

dfs需要熟记模板,需要注意初始化的问题,和记录走过的问题,细枝末节是WA发生的原因。

另外剪枝的问题也需要注意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值