当前位置: 代码迷 >> 综合 >> 1286: [蓝桥杯2016初赛]剪邮票 搜索与联通分量
  详细解决方案

1286: [蓝桥杯2016初赛]剪邮票 搜索与联通分量

热度:19   发布时间:2024-02-28 13:03:38.0

题目

题目链接

所遇问题

深搜

当时想到可以用dfs,但是发现答案不对,后来输出答案发现对于

在这里插入图片描述
这种情况没有
后来才想起对于深搜他会一直搜到底,
在这里插入图片描述
所以假如他搜索一开始走1这条路,走到底发现不够5个数,就会放弃这条路,然后递归一步一步退回去,再走2这条路,发现2这条路只有三个数可以选,所以说也放弃。但其实我们想要的答案是这两个路加起来。但是单纯的dfs不能实现。
当时这种思路难点在如何避免重复搜!!!

组合树

其实这个题相当于我从12个格子里选择五个格子,要去是这几个格子要连起来。也就相当于从0到11中选择5个数。
然后写了递归,但是对于1 2 3 4 5与5 4 3 2 1情况,按理说是一种情况,所以要组合不要排列。然后写了代码(错误的)

for(int i=p;i<=12;i++){
      //这样搜肯定有问题啊,因为12345 与54321会认为两个排列,那样的话求出来的是一样的啊 ,所以让//i从p开始,也就是说每次都将是升序排列的 if(mark[i]==0){
    mark[i]=1;a[step]=i;dfs(step+1,p+1);mark[i]=0;//a[step]=0;}}

然后还是有重复的
错误一:如果你在找一个数,但是i已经从第11个数开始循环找了,肯定找不够5个数了。
所以

for(int i=p;i<=12-(5-step);i++){
     //这个12-(5-step)(step表示搜索深度)

另一个,传参时,

	dfs(step+1,p+1);

正确的是

	dfs(step+1,i+1);
	for(int i=p;i<=12-(5-step);i++){
      a[step]=i;dfs(step+1,i+1);//这个地方,应该传i,这样组合出来的数是递增的}}

dfs判断连通度

就是搜多次,把能走到的地方都标记

void dfs_2(int x,int y){
    for(int i=0;i<4;i++){
    int dx=x+to[i][0];int dy=y+to[i][1];if(dx<0||dx>2||dy<0||dy>3||book_2[dx][dy]||book[dx][dy]==0){
    continue;}book_2[dx][dy]=true;dfs_2(dx,dy);}
}

ac代码

#include<bits/stdc++.h>
#include<cstring>
using namespace std;
int book[6][6];
int ans;
int a[5];
int mark[14];
int to[4][2]={
    {
    0,1},{
    1,0},{
    0,-1},{
    -1,0}};//右,下,左,不允许往上走,否则会有重复; 
bool book_2[6][6];
int parent[13];//并查集
void dfs_2(int x,int y){
    for(int i=0;i<4;i++){
    int dx=x+to[i][0];int dy=y+to[i][1];if(dx<0||dx>2||dy<0||dy>3||book_2[dx][dy]||book[dx][dy]==0){
    continue;}book_2[dx][dy]=true;dfs_2(dx,dy);}
}
bool judge(){
    memset(book,0,sizeof(book)) ;int dx,dy;int cnt;for(int i=0;i<5;i++){
     //把五个点标为1; dx=a[i]/4;dy=(a[i])%4;book[dx][dy]=1;}cnt=0;memset(book_2,false,sizeof(book_2));for(int i=0;i<3;i++){
    for(int j=0;j<4;j++){
    if(book[i][j]==1&&book_2[i][j]==false){
    dfs_2(i,j);cnt++;}}}if(cnt==1){
    return true;}else{
    return false;}// for(int i=0;i<=3;i++){
    
// for(int j=1;j<=4;j++){
    
// if(book[i][j]==1){
    
// if(book[i-1][j]==0&&book[i][j-1]==0&&book[i+1][j]==0&&book[i][j+1]==0){//这个方法是有问题的 
// return false;
// }
// }
// }
// }}
void dfs( int step,int p){
    if(step==5){
     //01234都放好了 if(judge() ){
    //判断是否符合题意
// for(int i=0;i<3;i++){
    
// for(int j=0;j<4;j++){
    
// cout<<book[i][j]<<" ";
// }
// cout<<endl;//调试的时候遇到换行就暂停 
// } 
// cout<<endl;
// for(int i=0;i<5;i++){
    
// cout<<a[i]<<" ";
// }
// cout<<endl<<endl;ans++;}return;}for(int i=p;i<=12-(5-step);i++){
      a[step]=i;dfs(step+1,i+1);}}int main(){
    dfs(0,0);cout<<ans<<endl;
}