CRPweek7周报

dfs用于解决连通性,路径查找,求解的个数

B3625 迷宫寻路

1.思路:用dfs寻找到一条路,不用回溯,因为我们只需要找到一条路就可以

2.代码:

#include <bits/stdc++.h>
using namespace std;
char a[105][105];
int vis[105][105];
int sx[4]={-1,0,1,0};
int sy[4]={0,1,0,-1};
int f=0;
int n,m;
void dfs(int x,int y)
{
	if(x==n&&y==m)
	{
		f=1;
        return;
	}
	else
	{
		for(int i=0;i<4;i=i+1)
		{
			int nx=x+sx[i];
			int ny=y+sy[i];
			if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[nx][ny]=='.'&&vis[nx][ny]==0)
			{
				vis[nx][ny]=1;
				dfs(nx,ny);
			}
		 } 
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i=i+1)
	{
		for(int j=1;j<=m;j=j+1)
		{
			cin>>a[i][j];
		}
	}
	vis[1][1]=1;
	dfs(1,1);
	if(f==0)
	{
		cout<<"No";
	}
	else
	{
		cout<<"Yes";
	}
}

P1706 全排列问题

1.思路:用dfs寻找到所有路径,即枚举出所有情况

2.代码:

#include <bits/stdc++.h>
using namespace std;
int a[1005];
int vis[1005];
void dfs(int n,int len,int num)
{
	if(num==n)
	{
		for(int i=1;i<=n;i=i+1)
		{
				cout<<"    "<<a[i];
			
			
			
		}
		cout<<endl;
	}
	else
	{
		for(int i=1;i<=n;i=i+1)
		{
			if(vis[i]==0)
			{
				vis[i]=1;
				num=num+1;
				a[num]=i;
				
				dfs(n,n,num);
				num=num-1;
				vis[i]=0;
			}
		}
	}
}
int main()
{
	int n;
	memset(vis,0,sizeof(vis));
	cin>>n;
	dfs(n,n,0);
}

P1451 求细胞数量

1.思路:求连通块的变形问题,所以我们可以用dfs求连通块,

2.代码:

#include <bits/stdc++.h>
using namespace std;
int n,m;
char a[105][105];
int sx[4]={-1,0,1,0};
int sy[4]={0,1,0,-1};
int vis[105][105];
void dfs(int x,int y)
{
	for(int i=0;i<4;i=i+1)
	{
		int nx=x+sx[i];
		int ny=y+sy[i];
		if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0&&a[nx][ny]!='0')
		{
			vis[nx][ny]=1;
			dfs(nx,ny);
		}
	}
	
}
int ans=0;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i=i+1)
	{
		for(int j=1;j<=m;j=j+1)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=n;i=i+1)
	{
		for(int j=1;j<=m;j=j+1)
		{
			if(vis[i][j]==0&&a[i][j]!='0')
			{
				vis[i][j]==1;
				ans++;
				dfs(i,j);
			}
		}
	}
	cout<<ans;
}

P1219 [USACO1.5] 八皇后 Checker Challenge

1.思路:分析这道题的条件:1.每行每列都只能有一个棋子 2.每个对角线都只能有一个棋子。所以我们要在每次dfs之前都要判断是否满足条件

2.代码:

#include <bits/stdc++.h>
using namespace std;
int visy[15];
int visc[30];
int visd[30];
int a[15][15];
int h[15];
int n;
int z;
int ans;
void dfs(int x)
{
	if(x==n+1)
	{
		if(z<3)
		{
			for(int i=1;i<=n;i=i+1)
			{
				if(i==n)
				{
					cout<<h[i];
				}
				else
				{
					cout<<h[i]<<" ";
				}
			}
			cout<<endl;
			z++;
		}
		ans++;
	}
	else
	{
		for(int i=1;i<=n;i=i+1)
		{
			if(visy[i]==0&&visc[x+i]==0&&visd[x-i+n]==0)
			{
				visy[i]=1;
				visc[x+i]=1;
				visd[x-i+n]=1;
				h[x]=i;
				dfs(x+1);
				h[x]=0;
				visy[i]=0;
				visc[x+i]=0;
				visd[x-i+n]=0;
			}
		}
	}
}
int main()
{
	cin>>n;
	dfs(1);
	cout<<ans;
}

P1019 [NOIP2000 提高组] 单词接龙

1.思路:分析题目条件:1.首尾有共同的部分可以连接 2.特殊情况:如果两个单词存在包含关系,那么不能连接。所以我们在进行dfs之前开一个二维数组,记录第i个单词是否能接第j个单词

2.代码:

P5194 [USACO05DEC] Scales S

1.思路:这是比较特殊的一类dfs,我称之为选择式dfs,我们在定义下一步的方向是选与不选,放左脑或右脑,另外,我们还可以加一个剪枝,即如果前面所有砝码都加起来都达不到当前的最大值,那么就可以停止搜索了,我们可以用前缀和来实现。

2.代码:

P1378 油滴扩展

1.思路:分析题目条件:1.扩展到接触其他油滴或者是边界即停止 2.油滴放置有先后顺序,且这个顺序由我们进行枚举 那么我们可以创建一个二维数组来存储每两个油滴之间的距离,在dfs中,来变化油滴之间的距离

2.代码:

#include <bits/stdc++.h>
using namespace std;
int n;
double cx1,cy1,cx2,cy2;
double x[7];
double y[7];
double d[7];
int vis[7];
int r[7];
int num1;
double h[7][7];
double max1;
void dfs(int s,double mian)
{
	if(s==n)
	{
		max1=max(max1,mian);
	}
	else
	{
		for(int i=1;i<=n;i=i+1)
		{
			if(vis[i]==0)
			{
				double min1=9999;
				int minx;
				for(int j=1;j<=num1;j=j+1)
				{
					if(h[i][r[j]]<min1)
					{
						min1=h[i][r[j]];
						minx=j;
					}
				}
				double min2=min(min1,d[i]);
				if(min2<0)
				{
					vis[i]=1;
					num1++;
					r[num1]=i;
					dfs(s+1,mian);
					r[num1]=0;
					num1--;
					vis[i]=0;
				}
				else
				{
					for(int j=1;j<=n;j=j+1)
					{
						if(i!=j)
						{
							h[j][i]=h[j][i]-min2;
						}
					}
					vis[i]=1;
					num1++;
					r[num1]=i;
					dfs(s+1,mian+3.1415926535*min2*min2);
					for(int j=1;j<=n;j=j+1)
					{
						if(i!=j)
						{
							h[j][i]=h[j][i]+min2;
						}
					}
					r[num1]=0;
					num1--;
					vis[i]=0;
				}
			}	
		}
	}
}
double juli(int x1,int y1,int x2,int y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
	cin>>n;
	cin>>cx1>>cy1>>cx2>>cy2;
	if(cx1>cx2)
	{
		int t=cx1;
		cx1=cx2;
		cx2=t;
	}
	if(cy1>cy2)
	{
		int t=cy1;
		cy1=cy2;
		cy2=t;
	}
	for(int i=1;i<=n;i=i+1)
	{
		cin>>x[i]>>y[i];
		d[i]=min(min(abs(x[i]-cx1),abs(x[i]-cx2)),min(abs(y[i]-cy1),abs(y[i]-cy2)));
	}
	for(int i=1;i<=n;i=i+1)
	{
		for(int j=i+1;j<=n;j=j+1)
		{
			h[i][j]=juli(x[i],y[i],x[j],y[j]);
			h[j][i]=h[i][j];
		}
	}
	dfs(0,0);
	cout<<fixed<<setprecision(0)<<(cx2-cx1)*(cy2-cy1)-max1;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值