连接:http://www.lydsy.com/JudgeOnline/problem.php?id=2064php
题意:求出从初状态到末状态最少操做次数。ios
首先咱们能够知道,次数在最坏状态下不会超过$n+m$次,即所有合并再所有分解。ide
在这种状况下,若是想要进一步缩小变化次数,那么就须要有一些子集,这些子集先后大小相等,从而减小进一步合并的次数两次。spa
那么就按照这个思路来好了。设$f[i][j]$为起始状态中状态为$i$的子集,终止状态为$j$的子集,常见的转移必定是枚举每一个子集……然而这样会$T$翻天……而后咱们仔细思考能够发现实际上最好的选择必定有一种方案就是只拿走一个元素……因而瞬间减小了$O(att^2)$的时间复杂度……而后若是当前子集相等可合并数再加一,最后结果就是$n+m-2*f[att1-1][att2-1],att1=(1<<n),att2=(1<<m)$。code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxa=1025; 7 int f[maxa][maxa],suma[maxa],sumb[maxa],n,m; 8 int lowbit(int x){return x&(-x);} 9 int haha() 10 { 11 scanf("%d",&n); 12 for(int i=0;i<n;i++) 13 { 14 int x;scanf("%d",&x); 15 suma[1<<i]=x; 16 } 17 scanf("%d",&m); 18 for(int i=0;i<m;i++) 19 { 20 int x;scanf("%d",&x); 21 sumb[1<<i]=x; 22 } 23 int att1=(1<<n),att2=(1<<m); 24 for(int i=1;i<att1;i++)suma[i]=suma[i^lowbit(i)]+suma[lowbit(i)]; 25 for(int i=1;i<att2;i++)sumb[i]=sumb[i^lowbit(i)]+sumb[lowbit(i)]; 26 for(int i=1;i<att1;i++) 27 for(int j=1;j<att2;j++) 28 { 29 for(int k=0;k<n;k++) 30 if(i&(1<<k))f[i][j]=max(f[i][j],f[i^(1<<k)][j]); 31 for(int k=0;k<m;k++) 32 if(j&(1<<k))f[i][j]=max(f[i][j],f[i][j^(1<<k)]); 33 if(suma[i]==sumb[j])f[i][j]++; 34 } 35 printf("%d\n",n+m-2*f[att1-1][att2-1]); 36 } 37 int sb=haha(); 38 int main(){;} 39