P3694 邦邦的大合唱站队
考察:状压dp
这也能状压?果然是我太弱了.
思路:
很容易想到压缩相同的数字,采取最暴力的做法就是将m个数字全排列计算代价的最小值.时间复杂度是O(m!)会T爆,所以需要优化.
假设有队列3个,我们队列顺序为1 2和队列顺序2 1,最后放3.可以发现如果确定了1 2和2 1的最小值后,放3的计算的值是确定的.也就是说,不管前面i个队列怎样排列组合,如果确定了前i个队列的最小值,那么计算i+1的最小值也很容易了.
因为先放1再放2与先放2再放1效果相同(对3),再结合m只有20可以联想到状压dp.由此就可以想到此题就是哈密顿路径的延伸题.f[i] 假设i为1101,那么代表就是前面放了124队列的最优解.
一定要预处理i状态下有哪些人,预处理和!!!因为一直T,所以剪了下枝...
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 const int N = 100010,M = 20; 5 int n,m,sum[M][N],cnt[1<<M]; 6 int f[1<<M]; 7 int main() 8 { 9 scanf("%d%d",&n,&m); 10 for(int i=1;i<=n;i++) 11 { 12 int x; scanf("%d",&x); 13 sum[x-1][i]++; 14 for(int j=0;j<m;j++) sum[j][i]+=sum[j][i-1]; 15 } 16 for(int i=1;i<1<<m;i++) 17 for(int j=0;j<m;j++) 18 if(i>>j&1) cnt[i]+=sum[j][n]; 19 memset(f,0x3f,sizeof f); 20 f[0] = 0; 21 for(int i=1;i<1<<m;i++) 22 for(int j=0;j<m;j++) 23 if(i>>j&1) 24 { 25 if(f[i-(1<<j)]>=0x3f3f3f3f) continue; 26 int len = cnt[i-(1<<j)]; 27 int now = len+sum[j][n]; 28 f[i] = min(f[i-(1<<j)]+now-len-sum[j][now]+sum[j][len],f[i]); 29 } 30 printf("%d\n",f[(1<<m)-1]); 31 return 0; 32 }