10817 - Headmaster's Headache(状态压缩)

举报
Linux猿 发表于 2021/08/05 00:45:03 2021/08/05
【摘要】 题目链接~~> 做题感悟:这题调试了天才AC掉,感觉自己处理字符串太麻烦了,检查了n遍,最后实在是找不出错误了就把代码的变量规范化了一下就AC了。 解题思路:                   首先,用 s*2 位数标记状态:前s位表示对应工作是否已经有一个教师在教了,后...

题目链接~~>

做题感悟:这题调试了天才AC掉,感觉自己处理字符串太麻烦了,检查了n遍,最后实在是找不出错误了就把代码的变量规范化了一下就AC了。

解题思路:

                  首先,用 s*2 位数标记状态:前s位表示对应工作是否已经有一个教师在教了,后s 位表示对应工作是否有两个教师在教课,大于两个就不必要记录,这样最多有 16 位标记数组完全开的下。然后就是类似背包滚动数组的做法,依次选择每个教师,并不断更新最优解,这里状态循环的时候要从大到小循环,因为如果从小到大就有可能重复使用一个教师(类似01背包的滚动数组)。

代码:


  
  1. #include<iostream>
  2. #include<ctime>
  3. #include<fstream>
  4. #include<sstream>
  5. #include<stack>
  6. #include<cstring>
  7. #include<map>
  8. #include<vector>
  9. #include<cstdio>
  10. #include<algorithm>
  11. using namespace std ;
  12. const int INF = 1000000000 ;
  13. const int MY = 100 + 10 ;
  14. const int MX = (1<<16) + 10 ;
  15. char s[MY] ;
  16. int n ,nx ,m ,Key ,sum ,n2 ;
  17. int dp[MX] ,num[MY] ,a[MY] ,w[MY] ;
  18. void solveA(char *s) // 处理字符串
  19. {
  20. bool flag = true ;
  21. int len = strlen(s) ,st = 0 ,end = len ;
  22. for(int i = 0 ;i < len ;i++)
  23. if((s[i] == ' ' || i == len-1) && st != end)
  24. {
  25. if(i == len-1)
  26. end = len ;
  27. else end = i ;
  28. int key = 0 ;
  29. for(int j = st ;j < end ;j++)
  30. key = key * 10 + s[j] - '0' ;
  31. if(flag) { sum += key ; flag = false ; }
  32. else num[key-1]++ ;
  33. st = i+1 ;
  34. }
  35. }
  36. void solveB(char *s ,int x) // 处理字符串
  37. {
  38. bool flag = true ;
  39. int len = strlen(s) ,st = 0 ,end = len ,K = 0 ;
  40. for(int i = 0 ;i < len ;i++)
  41. if((s[i] == ' ' || i == len-1) && st != end)
  42. {
  43. if(i == len-1)
  44. end = len ;
  45. else end = i ;
  46. int key = 0 ;
  47. for(int j = st ;j < end ;j++)
  48. key =key * 10 + s[j] - '0' ;
  49. if(flag) { flag = false ,w[x] = key ; }
  50. else K |= (1<<(key-1)) ;
  51. st = i+1 ;
  52. }
  53. a[x] = K ;
  54. }
  55. void input()
  56. {
  57. getchar() ;
  58. sum = 0 ; n2 = n*2 ;
  59. memset(num ,0 ,sizeof(num)) ;
  60. memset(a ,0 ,sizeof(a)) ;
  61. memset(w ,0 ,sizeof(w)) ;
  62. for(int i = 0 ;i < nx ;i++)
  63. {
  64. gets(s) ;
  65. solveA(s) ;
  66. }
  67. for(int i = 0 ;i < m ;i++)
  68. {
  69. gets(s) ;
  70. solveB(s ,i+1) ;
  71. }
  72. Key = 0 ;
  73. for(int i = 0 ;i < n ;i++)
  74. if(num[i]==1)
  75. Key |= (1<<i) ;
  76. else if(num[i] > 1)
  77. Key = Key |(1<<i) |(1<<(i+n)) ;
  78. memset(dp ,-1 ,sizeof(dp)) ;
  79. dp[0] = 0 ;
  80. }
  81. bool judge(int S1 ,int S)
  82. {
  83. int key = 0 ;
  84. for(int i = 0 ;i < n ;i++)
  85. if((!(S1 &(1<<i)) && (S &(1<<i)))||((S1 &(1<<i)) && !(S &(1<<i))))
  86. key |= (1<<i) ;
  87. else if((S1 &(1<<i)) && (S &(1<<i)))
  88. key = key |(1<<i) |(1<<(i+n)) ;
  89. key = key |S1 |S ;
  90. key = key &((1<<n2)-1) ;
  91. if(key == (1<<n2)-1)
  92. return true ;
  93. else return false ;
  94. }
  95. void DP()
  96. {
  97. int ans = INF ;
  98. if(Key == (1<<n2)-1) ans = 0 ;
  99. for(int i = 1 ;i <= m ;i++)
  100. for(int S = (1<<n2)-1 ;S >= 0 ;S--)
  101. if(dp[S] != -1)
  102. {
  103. int key = 0 ;
  104. for(int j = 0 ;j < n ;j++)
  105. if((!(S &(1<<j)) && (a[i] &(1<<j)))||((S &(1<<j)) && !(a[i] &(1<<j))))
  106. key |= (1<<j) ;
  107. else if((S &(1<<j)) && (a[i] &(1<<j)))
  108. key = key |(1<<j) |(1<<(j+n)) ;
  109. key |= S ;
  110. key &= ((1<<n2)-1) ; // 放止溢出
  111. if(dp[key] != -1)
  112. dp[key] = min(dp[key] ,dp[S] + w[i]) ;
  113. else dp[key] = dp[S] + w[i] ;
  114. if(dp[key] != -1 && judge(key ,Key))
  115. ans = min(ans ,dp[key]) ;
  116. }
  117. cout<<ans+sum<<endl ;
  118. }
  119. int main()
  120. {
  121. while(scanf("%d%d%d",&n ,&nx ,&m) ,n)
  122. {
  123. input() ;
  124. DP() ;
  125. }
  126. return 0 ;
  127. }


文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/38531959

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。