CSU 1973:给自己出题的小X(DFS或DP)

来源:互联网 发布:苹果版解压缩软件 编辑:程序博客网 时间:2024/06/10 19:52

给自己出题的小X

Time limit: 1 Sec Memory limit:128 Mb


Problem Description

小X学习了dfs,为了练习搜索,开始给自己出题玩。
玩着玩着,一会把自己难住了,一会又被自己难倒了,真是有趣诶!
小X出的题:
现在有N个不同的正整数,求它们可以组成多少个这样的集合,满足:

  • 集合内的元素数量S>1
  • 集合内任意两个数的差的绝对值都大于集合内的元素数量。

Input

第一行,一个正整数T(T<=20)表示数据组数。

对于每组数据,有两行。第一行为一个正整数N(3≤N≤25),第二行为N个用空格隔开的正整数xi(xi≤200)。

Output

对于每组数据,输出一行一个整数表示题中所描述的集合的个数。

Sample Input

1
5
2 3 5 8 1

Sample Output

6


题意:

给出N(N≤25)个不同的正整数,求有多少个这样的集合,集合内存在至少两个元素,且任意两个元素差值都大于集合内的元素数量。

解题思路:

以下是出题人的题解

正如题面中所描述的,出题人的意图是出一个搜索题。
该题,是按一定顺序枚举子集,然后检查子集是否合法。
时间上,子集数目最多为2N2N 个,判断是否合法可以在搜索过程中检查,因此时间复杂度为O(T*2N2N),T为数据组数。
不过根据题目数据范围xi≤200,合理地搜索一定可以剪枝,因此实际上搜索用时会低于极限复杂度,时间上可以接受。
具体来说:第一步还是先排个序,这样,“任意两个元素差值都大于集合内的元素数量”就等价于“排序后间隔最小的两个相邻元素差值大于集合内的元素数量”;
然后,可以从2开始枚举集合里的元素数目,在确定了元素数目之后dfs依次搜索第i个数,dfs过程中保证第i个数合法。
另外,不枚举集合内元素数目也是可以的,直接dfs依次枚举第i个数,当确定下一个数是否合法时,需要检查截止目前的最小相邻间隔是否大于目前集合内的元素数量。这一过程最好在dfs时记录并传递一个相邻间隔最小值。
值得一提的是,此题可以不用搜索完成,使用动态规划————事实上,在许多时候,指数级复杂度的搜索问题都可以尝试着用动态规划来解决。
其中一种动态规划方法是,定义dp[i][j][k] 表示前i个数里选j个数,并且第i个数要选,相邻最小间隔大于k的方案数。
初始化为 dp[i][1][k]=1(1iN,1kN)
状态转移方程是:

dp[i][j][k]=p=1idp[p][j1][k](a[i]a[p]>k)

答案为Ni=1Nk=2dp[i][k][k]
时间复杂度为O(N^4 )。

我的解法:DFS。先排序。用last记录上一个加入集合的下标,i记录当前准备用来加入集合的下标,s表示当前集合中元素数量,m表示当前集合中差的绝对值的最小值。如果当前元素可以加入,ans++,继续更新last,i,s和m后继续搜下一层。不管当前元素能不能加入,都要考虑不加入的情况,只有i+1,其他不变继续搜下一层。DP的方法有空再写写吧


Code:

#include <iostream>#include <algorithm>#include <cstdio>using namespace std;const int INF=1e8;int a[30];int ans=0;int n;void DFS(int last,int i,int s,int m){    if(i>=n||s<=0||m<=s)        return;    if(a[i]-a[last]>s+1&&m>s+1)    {        ans++;        DFS(i,i+1,s+1,min(m,a[i]-a[last]));    }    DFS(last,i+1,s,m);}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(int i=0;i<n;i++)            scanf("%d",a+i);        sort(a,a+n);        ans=0;        for(int i=0;i<n-1;i++)        {            DFS(i,i+1,1,INF);        }        printf("%d\n",ans);    }    return 0;}/**********************************************************************    Problem: 1973    User: HN0017    Language: C++    Result: AC    Time:112 ms    Memory:2020 kb**********************************************************************/