【YbtOJ】拔河比赛

题目链接:http://noip.ybtoj.com.cn/contest/16/problem/1

比较简单的一题,既然要深度优先搜索,那么就要考虑清楚几点:

  1. 递归或者说搜索的终止条件是什么?
  2. 这个递归或者说搜索有什么限制条件?
  3. 如何递归,又如何回溯?

我们从输入开始讲起:

 

Saction A     输入

题目中说的很明确,一共有T组样例,这种输入方法在NOIP的考试中很常见,但是有是有很容易产生假死(即循环仍在进行但是在运行窗口中显示什么都没有)的状态。这种输入可以采用while循环(当然for循环也可以)。

一般来说,这种多组数据的输入有主要的两种状态:

  1. 给定N组数据进行输入,N是输入的第一个数据。
  2. 同样给定N组数据进行输入,但是N是未知的。

同样的,有两种对应这两种输入的方法。

 

对于第一种,标准的用循环输入。

使用for循环时,第一个数据N先输入,然后开个for循环,重复N次,循环输入每一组的数据,程序如下:

1 cin>>N;
2 for(int i=1;i<=N;i++)
3 {
4   cin>>...  
5 }

使用while循环,同样输入一个数据N然后再while中递减。深入研究while,我们可以发现while后面的括号里装的是一个bool值,本质和if没什么区别,既然是bool值,那么就是一个真与假的判断:一开始输入N时,N可以大于0,也可以等于0。当N大于0时,没做一次循环,N就减一次(N--),直到其值为0,既然是0,那么判断为假,循环自然就结束了;当N等于0,循环在一开始就结束了,也可以理解为这个循环根本没有被执行,为了解决这个问题,就有了do...while()循环,程序如下:

1 cin>>N;
2 while(N--)
3 {
4   cin>>...
5 }

然而在使用这两种输入方法的时候会有一种很别扭的时候:N组数据下每一组还有M组数据,比如这题。这个时候开两个for或者两个while似乎都不太好,其实只要把两种嵌套就行了,嵌套顺序根据个人喜好而定,我个人喜欢在while里面套for。

 

对于第二种,不用说,肯定是要用while循环的。

很多人对于这种需要用Ctrl+Z来结束输入的题目没有什么好感,最主要的就是这种输入太容易造成runtime error!应对这种输入,我们需要有EOF的概念。所谓EOF就是end of file,通常在文本的最后存储,表示此字符资料结束,在这里换句话说就是输入结束了,而它在ascll中就是Ctrl+Z来表示的。

既然这个EOF存在于输入中(当然题目不可能傻到把“EOF”写到输入文件的末尾),那么只要我们读入到的东西为“EOF”就可以结束输入了。当然,你可能会人为需要用字符串(或字符串数组)来输入,因为“EOF”不是数字,但注意!“EOF”在ascll中是存在的,也就是说用int型的数据也可以读入“EOF”。程序如下:

1 while(scanf("%d",&N)!="EOF")  //注意,这输入只能用scanf!
2 {//写cin>>N!="EOF"是绝对错的!
3     cin>>...
4 }

 至于有些题目特意强调输入为‘0’或“end”之类的东西结束输入,只用把“EOF”换掉就行了。

Saction B     搜索

讲到这里,我们就不得不统一一下数据名和数据含义:

1 const int minn=INT_MAX;   //最小值,即最优答案
2 int T;   //应题目要求,共T组数据 
3 int n,ans,a[30]; //n应题目要求,ans表示最终答案,a数组表示每人的体重

首先,我们将ans的值定为最大即INT_MAX(这是老套路),接着就是dfs了。

dfs的深度不言而喻,肯定是n,也就是说,如果搜索的深度大于了n,那么肯定要确定答案并且提出函数,如果没有那么就可以继续搜索。

搜索中有五个关键,第一个是左边的人数,第二个是右边的人数,第三个是左边的总重量,第四个是右边的总重量,第五个是搜索深度。这五个值我们分别用lr,rr,ls,rs,x表示。

搜索两次:

  1. 第一次,搜索右边,深度+1,右边人数+1,右边重量+a[x]。
  2. 第二次,搜索左边,深度+1,左边人数+1,左边重量+a[x]。

这两次搜索并着写就行了。最关键的还是确定答案。如果x>n,就有两种可能:第一种,两边人数差的绝对值大于1,此时要直接回溯(return),但这种情况不多见。第二种,正常情况,取ans和两边重量差的绝对值两者中的最小值,回溯。

看吧,其实很简单的!

完整代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int minn=INT_MAX;
 4 int T,n,ans,a[30];
 5 void dfs(int x,int lr,int rr,int ls,int rs)
 6 {
 7     if(x>n)
 8     {
 9         if(abs(lr-rr)>1)
10             return;
11         ans=min(ans,abs(ls-rs));
12         return; 
13     }
14     dfs(x+1,lr,rr+1,ls,rs+a[x]);
15     dfs(x+1,lr+1,rr,ls+a[x],rs);
16 }
17 int main()
18 {
19     cin>>T;
20     while(T--)
21     {
22         ans=minn;
23         cin>>n;
24         for(int i=1;i<=n;i++)
25             cin>>a[i];
26         dfs(1,0,0,0,0);
27         cout<<ans<<endl;
28     }
29     return 0;
30 } 

 

posted on 2021-08-06 15:56  百里狂生  阅读(119)  评论(0编辑  收藏  举报

导航