DAY 5 搜索

搜索

开篇:

mayan游戏(noip2011 day1 T3)

这道题就是个码量题,老师讲题时淡淡的说写完前两题就花一个半小时了,最后一题不快点打会调不出来,对于一个三个半小时就写两题的蒟蒻来说这。。。。这题就是老师口中的简单题。。。。

这种消数游戏应该每个人都玩过,顾名思义,要消数,所以就要打一个消数函数,消完数,他上面的数又不能在空中飘着(他又不是蜘蛛侠),所以还要打一个下移函数,由于这两天玩洛谷版的2048,得出一个结论,下面的被消掉后,上面的掉下来若能消还会继续消,直到不能消为止,所以还要一个判断有没有消完的函数,这题一看就知道要DFS,所以DFS怎么可以少。

但这题空间就128MB,时间也是巨卡,没有优化怎么能过?DFS这个东西十分神奇,因为他可以莫名其妙的剪枝(剪得你都不认识他了)

然后,你就可以打出这样的代码,一遍不过就重打吧。。。。。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 using namespace std;
  7 const int maxn=10;
  8 int mayan[maxn][maxn];
  9 int xxx;
 10 int ans[maxn][maxn];
 11 int n;
 12 inline int is_clear()
 13 {
 14     for(int i=0;i<5;i++)
 15     {
 16         for(int j=0;j<7;j++)
 17         {
 18             if(mayan[i][j])
 19             {
 20                 return 0;
 21             }
 22         }
 23     }
 24     return 1;
 25 }
 26 void new_ans(int i,int x,int y,int flag)
 27 {
 28     ans[i][1]=x;
 29     ans[i][2]=y;
 30     ans[i][3]=flag;
 31 }
 32 void fell_down(int x)
 33 {
 34     int tot=-1;
 35     for(int i=0;i<7;i++)
 36     {
 37         if(mayan[x][i])
 38         {
 39             mayan[x][++tot]=mayan[x][i];
 40         }
 41     }
 42     for(int i=tot+1;i<7;i++)
 43     {
 44         mayan[x][i]=0;
 45     }
 46     return ;
 47 }
 48 void clear() {
 49     bool flag = true;
 50     while(flag) {
 51         flag = false;
 52         int temp[10][10];
 53         memcpy(temp,mayan,sizeof(temp));
 54         for(int i=0;i<5;i++)
 55             for(int j=0;j<7;j++) 
 56             {
 57                 if(i >= 1 && i <= 3 && temp[i][j] && temp[i][j] == temp[i-1][j] && temp[i][j] == temp[i+1][j]) {
 58                     mayan[i][j] = 0;
 59                     mayan[i-1][j] = 0;
 60                     mayan[i+1][j] = 0;
 61                     flag = true;
 62                 }
 63                 if(j >= 1 && j <= 5 && temp[i][j] && temp[i][j] == temp[i][j-1] && temp[i][j] == temp[i][j+1]) {
 64                     mayan[i][j] = 0;
 65                     mayan[i][j-1] = 0;
 66                     mayan[i][j+1] = 0;
 67                     flag = true;
 68                 }
 69             }
 70                 
 71         if(!flag)
 72            return;
 73         for(int i=0;i<5;i++)
 74             fell_down(i);
 75     }
 76 }
 77 void dfs(int x)
 78 {
 79     if(is_clear()&&x==n)
 80     {
 81         for(int i=1;i<=x;i++)
 82         {
 83             cout<<ans[i][1]<<" "<<ans[i][2]<<" "<<ans[i][3]<<endl;
 84             xxx=1;
 85         }
 86         exit(0);
 87     }
 88     if(x>=n)
 89     {
 90         return ;
 91     }
 92     int temp[10][10];
 93     memcpy(temp,mayan,sizeof(temp));
 94     for(int i=0;i<5;i++)
 95     {
 96         for(int j=0;j<7;j++)
 97         {
 98             if(!mayan[i][j])
 99             {
100                 continue;
101             }
102             if(i!=4)
103             {
104                 swap(mayan[i][j],mayan[i+1][j]);
105                 fell_down(i);
106                 fell_down(i+1);
107                 clear();
108                 new_ans(x+1,i,j,1);
109                 dfs(x+1);
110                 new_ans(x+1,0,0,0);
111                 memcpy(mayan,temp,sizeof(mayan));
112             }
113             if(i&&!mayan[i-1][j]) 
114             {
115                 swap(mayan[i][j],mayan[i-1][j]);
116                 fell_down(i);
117                 fell_down(i - 1);
118                 clear();
119                 new_ans(x+1,i,j,-1);
120                 dfs(x + 1);
121                 new_ans(x+1,0,0,0);
122                 memcpy(mayan,temp,sizeof(mayan));
123             }
124         }
125         
126     }
127 }
128 int main()
129 {
130     cin>>n;
131     for(int i=0;i<5;i++)
132     {
133         int p=0;
134         do
135         {
136             cin>>mayan[i][p];
137             p++;
138         }while(mayan[i][p-1]!=0);
139     }
140     dfs(0);
141     if(xxx!=1)
142     {
143         cout<<-1<<endl;
144     }
145 }

拓展:剪枝

  • DFS专用,BFS就不用想了。
  • 可行性剪枝:如果已经判断这下面的都不合法,就可以剪枝。
  • 最优性剪枝:如果下面的答案一定不会比当前更优,剪枝
  • 搜索的顺序对剪枝会有很大影响。

一些好到无话可说的好题目:

  1. NOIP2015 斗地主
  • 如果当前的出牌数已经超过了最优的ans,剪枝(最优性剪枝)
  • 搜索顺序:先顺子,之后就不用记录牌的大小了,只要记录张数有1,2,3,4的分别有几种就可以了。
  • 之后先打牌数多的,先打四带二,再打三带一,也就是说一旦打出三代一,以后就不可能打出四带二了。
  • 每次搜索开始时,用当前的出牌数加上不同点数的牌的数量更新ans。

代码

         2.切蛋糕(IOI 1999)

这是道名题啊!!!!!

IOI啊!!!!

不过也确实时20年前的题目了,要是放到现在,那想游客这样的大佬也不会天天说AKIOI了,但在当年确实怪难,那剪枝,鬼畜。

  • 搜索顺序 :从最下面一层开始,一层一层向上搜,枚举最下面的半径和高度最大。
  • 以算好的答案(最小面积)减去蛋糕当前层以下的总面积若小于上面所能构成的最小面积,就剪枝(最优性剪枝)
  • 总体积减去当前层以下的总体积小于上面所能构成的最小体积,剪枝(可行性剪枝)

         3.小木棍(加强版)

这是一个好题目 ,那个天天AKIOI的游客(因为是机房大佬,所以不得不膜)竟然运用运动会的时间,花了一下午没打出来,真好奇他当时有没有对电脑进行了某种报复行为。。。。

  •  暴力思路,一个一个枚举长度x,看能不能填满sum/x根木棍。
  • 剪枝1:X必须是sum的因数,且X>=maxlen。
  • 剪枝2:将木棍降序排列,优先填更长的。

猜你喜欢

转载自www.cnblogs.com/2529102757ab/p/11246221.html