CodeForces 279D The Minimum Number of Variables 题解

题目大意:

  有一组n个不相同的数字组成数串:a1,a2,a3…an

  1.一个数组b。

  2.第一个操作我们将b0的值赋为a1。之后我们有n-1个操作,第k次操作我们将by=bi+bj(y,i,j可能相同)。

  3.每次操作结束后我们依次取出by。按顺序组成新串。

      问操作结束后,我们获得的新串能否与a数串相同。如果可以输出数组b所需的最小长度。反之输出-1。

思路:

  先介绍一个纯dfs的算法:每次依次枚举i,j,y,然而会T。

  不过,可以发现,b中的数必定在a中出现过。因此,记忆化搜索,状态(s)中存的是a1到an是否在b中,则s中1的个数即为b的长度。之后进行dfs,当然每种状态只需搜到一次。

  记住:by,bi,bj可以在已有的b中任取!

  有两种方式:

  1.顺着,每次check一下第k个能否得到,之后dfs,但check复杂度较高。

  2.倒着,从第n个数倒推,取子状态中最小的,再与当前的进行判断。

代码:

  顺着:

 1 #include<cstdio>
 2 int n,i,ans,a[25],mi[25];
 3 bool vis[1<<23];
 4 
 5 bool check(int s,int k)
 6 {
 7     for (int i=0;i<n;++i)
 8         for (int j=i;j<n;++j)
 9             if ((mi[i]&s) && (mi[j]&s) && (a[i]+a[j]==a[k])) return 0;
10     return 1;
11 }
12 
13 void dfs(int k,int s)//s Status
14 {
15     if (vis[s]) return;
16     int i,cnt=0; vis[s]=1;
17     for (i=s;i;i=i>>1) cnt=cnt+(i&1);
18     if (ans<=cnt) return;
19     if (k==n) { ans=cnt; return; }
20     if (check(s,k)) return;
21     dfs(k+1,s|mi[k]);
22     for (i=0;i<n;++i)
23         if (s&mi[i]) dfs(k+1,(s^mi[i])|mi[k]);
24 }
25 
26 int main()
27 {
28     scanf("%d",&n);
29     for (i=0;i<n;++i) scanf("%d",&a[i]);
30     for (mi[0]=i=1;i<=n;++i) mi[i]=mi[i-1]<<1;
31     ans=30; dfs(1,1); printf("%d
",ans<30?ans:-1);
32     return 0;
33 }

  倒着:

 1 #include<cstdio>
 2 const int M=24;
 3 int n,i,a[M],mi[M],dp[1<<M];
 4 
 5 void dfs(int k,int s)
 6 {
 7     if (dp[s]) return;
 8     dp[s]=M; int i,j,t;
 9     for (i=0;i<k;++i)
10         for (j=i;j<k;++j)
11             if (a[i]+a[j]==a[k])
12             {
13                 t=(s-mi[k]) | mi[i] | mi[j] | mi[k-1];
14                 dfs(k-1,t);
15                 if (dp[s]>dp[t]) dp[s]=dp[t];
16             }
17     for (t=0,i=s;i;i=i>>1) t=t+(i&1);
18     if (dp[s]<t) dp[s]=t;
19 }
20 
21 int main()
22 {
23     scanf("%d",&n);
24     for (mi[0]=i=1;i<=n;++i) mi[i]=mi[i-1]<<1;
25     for (i=0;i<n;++i) scanf("%d",&a[i]);
26     --n,dp[1]=1,dfs(n,mi[n]);
27     if (dp[mi[n]]==M) printf("-1
");
28     else printf("%d
",dp[mi[n]]);
29     return 0;
30 }
原文地址:https://www.cnblogs.com/HHshy/p/6013266.html