1. 程式人生 > >【2018百度之星資格賽】 A 問卷調查 - 位運算&動規

【2018百度之星資格賽】 A 問卷調查 - 位運算&動規

blog 題目 相同 clas 方程 數組 cstring div col

題目地址:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=820&pid=1001

參考博客:在此感謝http://www.cnblogs.com/LQLlulu/p/9419232.html博主,多謝指教,受益良多

Summarize:

  1. 使用動態規劃的方法,狀態轉移方程:f[i][p]=f[i-1][p]+i-和第i個答案集合相同的數目;

  2. 轉移方程中i表示第i份答卷,p表示被選中問題集合,因為每個問題只有A,B兩種答案,故可使用二進制表示,1表示選‘A’,2表示選‘B’;

  3. p則表示問題集合,從01至(1<<m)-1循環;

  4. “+i”表示假設前i份問卷都與i不同(包括i本身);

  5. PS: 註意數組範圍,雖然題目只給了n在1000以內,但通過剛才的分析我們發現,vis數組因為開到了(1<<m)-1,所以至少要開到1<<m,即1024!!

附代碼:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5
using namespace std; 6 7 #define LL long long 8 const int N = 1025; 9 int T, n, m, k, f[N][1<<11], vis[N]; 10 char text[N][15]; 11 12 int main() 13 { 14 scanf("%d", &T); 15 for(int t=1; t<=T; t++) 16 { 17 scanf("%d%d%d", &n, &m, &k); 18 19
for(int i=1; i<=n; i++) 20 scanf("%s", text[i]); 21 22 int all = (1<<m)-1; 23 for(int p=0; p<=all; p++) { 24 memset(vis, 0, sizeof(vis)); 25 for(int i=1; i<=n; i++) { 26 int w=0; 27 for(int j=0; j<m; j++) { 28 if( p&(1<<j) && text[i][j]==A) 29 w|=(1<<j); 30 } 31 vis[w]++; 32 f[i][p] = f[i-1][p]+i-vis[w]; 33 34 } 35 } 36 37 int ans=0; 38 for(int i=0; i<(1<<m); i++) 39 if(f[n][i]>=k) 40 ans++; 41 printf("Case #%d: %d\n", t, ans); 42 } 43 44 return 0; 45 }

【2018百度之星資格賽】 A 問卷調查 - 位運算&動規