DFS
1.走出迷宫-NC14572
小明现在在玩一个游戏,游戏来到了教学关卡,迷宫是一个N*M的矩阵。 小明的起点在地图中用“S”来表示,终点用“E”来表示,障碍物用“#”来表示,空地用“.”来表示。 障碍物不能通过。小明如果现在在点(x,y)处,那么下一步只能走到相邻的四个格子中的某一个:(x+1,y),(x-1,y),(x,y+1),(x,y-1); 小明想要知道,现在他能否从起点走到终点。
输入描述:
本题包含多组数据。每组数据先输入两个数字N,M接下来N行,每行M个字符,表示地图的状态。数据范围:2<=N,M<=500保证有一个起点S,同时保证有一个终点E.
输出描述:
每组数据输出一行,如果小明能够从起点走到终点,那么输出Yes,否则输出No
输入:
3 3
S…
…E
…
3 3
S##
##E
输出:
Yes
No
#include<bits/stdc++.h>
#include<time.h>
#include<iostream>
#include<ostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define maxn 10000000
typedef long long ll;
const int INF=0x7fffffff;//2147483647
const int SUP=0x80000000;//-2147483648
#define loop(a,b,i) for(int i=a;i<b;i++)
#define loopx(a,b,i) for(int i=a;i<=b;i++)
#define lson (p<<1)
#define rson ((p<<1)|1)
#define mid ((l+r)>>1)
#define MAX 100005
char dfs[505][505];
int dir[4][2]={1,0,-1,0,0,-1,0,1};
int n,m,flag;
void DFS(int x,int y)
{
for(int i=0;i<4;i++)
{
int X=x+dir[i][0],Y=y+dir[i][1];
if(X>=0&&X<n&&Y>=0&&Y<m&&dfs[X][Y]!='#'&&dfs[X][Y]!='1')
{
if(dfs[X][Y]=='E')flag=1;
dfs[X][Y]='1';
DFS(X,Y);
}
}
}
int main()
{
while(cin>>n>>m)
{
int x,y;
memset(dfs,'0',sizeof(dfs));
flag=0;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
{
cin>>dfs[i][j];
if (dfs[i][j]=='S')
{
x=i;y=j;
}
}
DFS(x,y);
if(flag)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
2.数芝麻-NC14591
有天糖在宿舍闲着没事, 拿出粉笔在地上画了n*n个方格, 每个方格放上一定数量的芝麻, 并规定如果两个方格相邻且都有芝麻,那这两个方块都属于同一片区域。现在问你的是, 有没有存在这样的区域, 它的芝麻的总数量为m
输入描述:
有多组数据,每组数据第一行为n(n<=100)和m, 接下来有n行n列数据, 每个数字代表每个方格里的芝麻数量,, 当n和m等于0时结束输入。
输出描述:
对于每一组数据,输出一行,如果能找这样的区域, 输出”YES”, 否则输出“NO”。
输入:
3 2
1 0 0
1 0 1
1 0 1
0 0
输出:
YES
#include<bits/stdc++.h>
#include<time.h>
#include<iostream>
#include<ostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define maxn 10000000
typedef long long ll;
const int INF=0x7fffffff;//2147483647
const int SUP=0x80000000;//-2147483648
#define loop(a,b,i) for(int i=a;i<b;i++)
#define loopx(a,b,i) for(int i=a;i<=b;i++)
#define lson (p<<1)
#define rson ((p<<1)|1)
#define mid ((l+r)>>1)
#define MAX 100005
int dfs[505][505];
int D[105][105];
int dir[8][2]={1,0,-1,0,0,-1,0,1};
int n,m,flag,sum;
void DFS(int x,int y)
{
if(D[x][y]==1||dfs[x][y]==0||x<0||x>=n||y<0||y>=n)return;
D[x][y]=1;
sum+=dfs[x][y];
for(int i=0;i<4;i++)
{
int X=x+dir[i][0],Y=y+dir[i][1];
DFS(X,Y);
}
}
int main()
{
while(cin>>n>>m)
{
if(n==0&&m==0)break;
int x,y;
memset(dfs,0,sizeof(dfs));
memset(D,0,sizeof(D));
flag=0;
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
{
cin>>dfs[i][j];
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
sum=0;
DFS(i,j);
if(sum==m)flag=1;
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
3.邮票面值设计-NC16813(dp+dfs)
给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1至MAX之间的每一个邮资值都能得到。 例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和 12分);如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以 MAX=7,面值分别为1分、3分。
输入描述:
1行。2个整数,代表N,K。
输出描述:
2行。第一行若干个数字,表示选择的面值,从小到大排序。第二行,输出“MAX=S”,S表示最大的面值。
输入:
3 2
输出:
1 3
MAX=7
思路:
1.首先面值里边必有1,故a[1]=1
2.其次直接枚举暴力会超时,故用dp来找到每次搜索的上确界进行搜素剪枝
#include<bits/stdc++.h>
#include<time.h>
#include<iostream>
#include<ostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define maxn 10000000
typedef long long ll;
const int INF=0x7fffffff;//2147483647
const int SUP=0x80000000;//-2147483648
#define loop(a,b,i) for(int i=a;i<b;i++)
#define loopx(a,b,i) for(int i=a;i<=b;i++)
#define lson (p<<1)
#define rson ((p<<1)|1)
#define mid ((l+r)>>1)
#define MAX 100005
char mapp[50][50];
//int dir[8][2]={1,0,-1,0,0,-1,0,1,1,1,1,-1,-1,1,-1,-1};
int n,K;
int a[20];//存储邮票面值
int ans[20];//存储结果
int dp[50000];//储存组成x的邮票最小张数(dp[x])
int maxx=0;//连续邮资最大值
int DP(int k)//找到k种类个数时的连续邮资最大值(搜索剪枝)
{
memset(dp,63,sizeof(dp));dp[0]=0;
for(int i=1;i<=k;i++)
for(int j=a[i];j<=a[k]*n;j++)
if(dp[j-a[i]]<n)
dp[j]=min(dp[j],dp[j-a[i]]+1);
int x=1;
while(dp[x]<=20)x++;//得到k种时的连续邮资最大值
return x-1;//返回k种时连续邮资最大值
}
void dfs(int k)//找到满足条件的最大连续邮资数
{
if(k==K+1)
{
int t=DP(K);
if(t>maxx)
{
maxx=t;
memcpy(ans,a,sizeof(a));
}
return ;
}
int end=DP(k-1);//前一种类数所能达到的最大连续邮资数
for(int i=a[k-1]+1;i<=end+1;i++)//枚举并向下搜索
{
a[k]=i;dfs(k+1);
}
}
int main()
{
cin>>n>>K;
a[1]=1;
dfs(2);
for(int i=1;i<=K;i++)cout<<ans[i]<<" ";
cout<<endl<<"MAX="<<maxx;
return 0;
}
4.小H和游戏-NC15158(树+dfs+并查集思想)
小H正在玩一个战略类游戏,她可以操纵己方的飞机对敌国的N座城市(编号为1~N)进行轰炸 敌国的城市形成了一棵树,小H会依次进行Q次轰炸,每次会选择一个城市A进行轰炸,和这座城市距离不超过2的城市都会受损(这里距离的定义是两点最短路径上的边数),轰炸结束后,小H还想知道当前城市A受损的次数 作为游戏的开发者之一,你有义务回答小H的问题
输入描述:
第1行,两个整数N(1≤N≤750000)、Q(1≤Q≤750000)第2到N行,每行两个整数表示树上的一条边第N+1~N+Q行,每行一个整数,表示小H这次轰炸的城市。
输出描述:
输出Q行,每行一个整数表示这一次轰炸的城市在此次轰炸后共计受损几次。
输入:
4 4
1 2
2 3
3 4
1
2
3
4
输出:
1
2
3
3
思路:
定义:直接受损:x直接被轰炸 间接受损:x被相邻节点波及
1.用vector二维数组存储x的所有邻接点vector[x]
2.dfs(x,f)找x的父节点
3.cnt数组含义
cnt[x][0]–自己受损
cnt[x][1]–儿子受损
cnt[x][2]–孙子受损
4.每次询问节点x需要的操作:
①x会波及他的儿子和孙子:cnt[x][1]++;cnt[x][2]++;代表这是x波及的。
②x会波及父亲:cnt[fa[x]][0]++;
③用cnt[fa[x]][1]++;储存x直接受损,用父节点存储原因看5.
④x会波及到爷爷:cnt[fa[fa[x]]][0]++;
5.通过3.可以看出:
①cnt[x][0]代表x的儿子波及给x+x孙子波及给x
②cnt[fa[x]][1]代表x直接受损+x父亲因自身受损波及x受损。
所以用父节点存储儿子的直接受损。
故cnt[fa[x]][1]=x直接受损+x父亲直接受损所波及给x
③cnt[fa[fa[x]]][2]代表x的爷爷波及给x的
综上当前x受损数=x儿子和孙子波及给x的+x直接受损和父亲波及给x的+x爷爷波及给x的=cnt[x][0]+cnt[fa[x]][1]+cnt[fa[fa[x]][2]
#include<bits/stdc++.h>
#include<time.h>
#include<cctype>
#include<iostream>
#include<ostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define maxn 10000000
typedef long long ll;
const int INF=0x7fffffff;//2147483647
const int SUP=0x80000000;//-2147483648
#define loop(a,b,i) for(int i=a;i<b;i++)
#define loopx(a,b,i) for(int i=a;i<=b;i++)
#define lson (p<<1)
#define rson ((p<<1)|1)
#define mid ((l+r)>>1)
#define MAX 100005
//char mapp[1005][1005];
//int dir[8][2]={1,0,-1,0,0,-1,0,1,1,1,1,-1,-1,1,-1,-1};
const int inf = 750010;
int n,q;
int maxx=0;
int cnt[inf][3];//存储该节点破损次数
//(cnt[x][0]--本身 cnt[x][1]--儿子 cnt[x][2]--孙子)
int fa[inf];//x的父亲是谁
vector<int>que[inf];//二维数组,存储树,节点关系
void dfs(int x,int f)//找x的父亲
{
fa[x]=f;
for(auto i : que[x])//遍历和x相邻节点
{
if(i==f)continue;//排除x的父亲
else dfs(i,x);
}
}
void solve()//询问
{
dfs(1,0);//1的父亲是0
memset(cnt,0,sizeof(cnt));
while(q--)
{
int x;
cin >> x;
//cnt[x][0]--本身 cnt[x][1]--儿子 cnt[x][2]--孙子
cnt[x][1]++;cnt[x][2]++;//x波及x的儿子和孙子,但不记录x自身
cnt[fa[x]][0]++; cnt[fa[x]][1]++;//x父亲被波及破损,再将x直接破损记录在父节点上,这样父节点就可以表现x破损情况
cnt[fa[fa[x]]][0]++;//x爷爷被x波及破损
int s=cnt[x][0] + cnt[fa[x]][1] + cnt[fa[fa[x]]][2];
//s=x被儿子或者孙子波及到次数+自身破损次数和受父亲波及+受爷爷波及
cout<<s<<endl;
}
}
int main()
{
cin>>n>>q;
int x,y;
for(int i=1;i<=n-1;i++)
{
cin>>x>>y;
que[x].push_back(y);//记录x相邻节点
que[y].push_back(x);//记录y相邻节点
}
solve();
return 0;
}
5.乌龟跑步-NC15294(四维数组dfs)
有一只乌龟,初始在0的位置向右跑。 这只乌龟会依次接到一串指令,指令T表示向后转,指令F表示向前移动一个单位。乌龟不能忽视任何指令。 现在我们要修改其中正好n个指令(一个指令可以被改多次,一次修改定义为把某一个T变成F或把某一个F变成T)。 求这只乌龟在结束的时候离起点的最远距离。(假设乌龟最后的位置为x,我们想要abs(x)最大,输出最大的abs(x))
输入描述:
第一行一个字符串c表示指令串。c只由F和T构成。第二行一个整数n。1 <= |c| <= 100, 1 <= n <= 50
输出描述:
一个数字表示答案。
输入:
FT
1
FFFTFFF
2
输出:
2
6
思路:
定义四个参数的dfs:①当前字符串位置②剩余操作数③乌龟位置④面朝方向(1右0左)
#include<bits/stdc++.h>
using namespace std;
string h;
int n;
int length;
bool dp[105][55][205][2];
int ans=0;
void dfs(int def,int n,int pos,int way)
{
if(def==length)//当走到字符串最末尾的时候
{
if((n%2)==0) ans=max(ans,abs(pos));
//判断是否剩余步骤数是2的倍数,因为只要是2的倍数,随便选取一个,
//比如F,先改为T,再改为F,每改两次便会回到原来的,
//故只要是2的倍数就能保证和剩余0操作步骤是一样的。
return;
}
if(n<0||dp[def][n][pos][way]) return;//如果操作步数小于0说明上一次改写错误,即没有操作数却改变字符。
//不可以n<=0,因为若n=0,上一步是正确的,可能改了也可能没改,但这一步没有操作数了,只能选择不改。
dp[def][n][pos][way]=1;//标记目前的状态,下次再到该状态的时候便停止
if(h[def]=='F')
{
if(way==0)
{
dfs(def+1,n-1,pos,1);
//改变:字符串向前,操作数-1,位置不便(由前进变为改方向),方向变为正向1
dfs(def+1,n,pos-1,0);
//不改变:字符串向前,操作数不变,位置向后退,方向不变保持负方向
}
else
{
dfs(def+1,n-1,pos,0);
//改变:字符串向前,操作数-1,位置不便(由前进变为改方向),方向变为负向0
dfs(def+1,n,pos+1,1);
//不改变:字符串向前,操作数不变,位置向前进,方向不变保持正方向
}
}
else
{
if(way==0)
{
dfs(def+1,n-1,pos-1,0);
dfs(def+1,n,pos,1);
}
else
{
dfs(def+1,n-1,pos+1,1);
dfs(def+1,n,pos,0);
}
}
}
int main()
{
cin>>h>>n;
length=h.size();
memset(dp,0,sizeof(dp));//先初始化为0
dfs(0,n,0,1);//开始字符串位置在0,有n个操作次数,乌龟位置为0,方向为正方向1
cout<<ans<<endl;
}