HDU 4770 Lights Against Dudely -- 2013 杭州赛区现场赛-A(状态压缩)

举报
Linux猿 发表于 2021/08/04 23:22:47 2021/08/04
【摘要】 题目链接~~> 做题感悟:以前在杭州赛区重现赛时做过这题,当时只知道暴力,而且没有看到有一盏特殊灯,结果以两题结束。 解题思路:因为只有 15 盏灯,可以用状态压缩,枚举每一种情况(在其中还要枚举特殊灯),参考了一下某大牛的代码才AC。 代码: #include<stdio.h>#include<queue>#include<str...

题目链接~~>

做题感悟:以前在杭州赛区重现赛时做过这题,当时只知道暴力,而且没有看到有一盏特殊灯,结果以两题结束。

解题思路:因为只有 15 盏灯,可以用状态压缩,枚举每一种情况(在其中还要枚举特殊灯),参考了一下某大牛的代码才AC。

代码:


  
  1. #include<stdio.h>
  2. #include<queue>
  3. #include<string.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<algorithm>
  7. #include<iostream>
  8. #define INT long long int
  9. const int INF = 99999999 ;
  10. using namespace std ;
  11. const int MX = 200 + 10 ;
  12. typedef pair<int,int> PI;
  13. vector<PI>v ;
  14. bool IS[MX] ;
  15. int n,m,M ;
  16. char s[MX][MX] ;
  17. int vis[MX],d[MX][MX] ;
  18. int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1} ; // 上 右 下 左 0 1 2 3
  19. bool judge()
  20. {
  21. for(int i=0 ;i<M ;i++)
  22. if(!vis[i]) return false ;
  23. return true ;
  24. }
  25. void put(int x,int y,int px,int py)// 安放一般灯
  26. {
  27. int sx,sy,tx,cnt=d[x][y] ;
  28. int dn[2]={px,py} ;
  29. bool flag=false ; // 用来判断是否可以放
  30. for(int i=0 ;i<2 ;i++) // 判断是否可以放
  31. {
  32. tx=dn[i] ;
  33. sx=x+dx[tx] ;
  34. sy=y+dy[tx] ;
  35. if(sx<0||sy<0||sx>=n||sy>=m) continue ;
  36. if(s[sx][sy]=='#')
  37. {
  38. flag=true ;
  39. break ;
  40. }
  41. }
  42. if(!flag) // 可以放
  43. {
  44. vis[cnt]++ ;
  45. IS[cnt]=true ;
  46. for(int i=0 ;i<2 ;i++)
  47. {
  48. tx=dn[i] ;
  49. sx=x+dx[tx] ;
  50. sy=y+dy[tx] ;
  51. if(sx<0||sy<0||sx>=n||sy>=m) continue ;
  52. vis[d[sx][sy]]++ ;
  53. }
  54. }
  55. }
  56. void clear(int x,int y,int px,int py) // 清除
  57. {
  58. int sx,sy,tx,dn[2]={px,py} ;
  59. IS[d[x][y]]=false ;
  60. vis[d[x][y]]-- ;
  61. for(int i=0 ;i<2 ;i++)
  62. {
  63. tx=dn[i] ;
  64. sx=x+dx[tx] ;
  65. sy=y+dy[tx] ;
  66. if(sx<0||sy<0||sx>=n||sy>=m) continue ;
  67. vis[d[sx][sy]]-- ;
  68. }
  69. }
  70. void work(int x,int y,int px,int py,int nx,int ny) // 安放特殊灯
  71. {
  72. int cnt = d[x][y] ;
  73. if(IS[cnt]) // 说明安放过
  74. clear(x,y,px,py) ;// 清除以前安放的灯以及灯光
  75. put(x,y,nx,ny) ; // 安放
  76. }
  77. int main()
  78. {
  79. while(scanf("%d%d",&n,&m),(n||m))
  80. {
  81. M=0 ;
  82. v.clear() ;
  83. memset(d,0,sizeof(d)) ;
  84. for(int i=0 ;i<n ;i++)
  85. {
  86. scanf("%s",s[i]) ;
  87. for(int j=0 ;j<m ;j++)
  88. if(s[i][j]=='.')
  89. {
  90. d[i][j]=M++ ;
  91. v.push_back(make_pair(i,j)) ;
  92. }
  93. }
  94. if(!M)
  95. {
  96. cout<<0<<endl ;
  97. continue ;
  98. }
  99. int ans=INF ;
  100. for(int i=0 ;i<(1<<M) ;i++) // 枚举各种状态
  101. {
  102. int num=0 ;
  103. memset(vis,0,sizeof(vis)) ;
  104. memset(IS,false,sizeof(IS)) ;
  105. for(int j=0 ;j<M ;j++)
  106. if((1<<j)&i)
  107. {
  108. num++ ; // 记录灯的个数
  109. put(v[j].first,v[j].second,0,1) ; // 放普通灯
  110. }
  111. if(num>=ans) continue ;
  112. if(judge()) ans = min(ans,num) ;
  113. else // 安放特殊灯
  114. {
  115. for(int j=0 ;j<M ;j++) // 尝试每个灯
  116. if((1<<j)&i)
  117. {
  118. work(v[j].first,v[j].second,0,1,1,2) ; //清除上 右 / 安放 右 下
  119. if(judge()) { ans = min(ans,num) ; break ; }
  120. work(v[j].first,v[j].second,1,2,2,3) ; //清除 右 下 / 安放 左 下
  121. if(judge()) { ans = min(ans,num) ; break ; }
  122. work(v[j].first,v[j].second,2,3,0,3) ; //清除 左 下 / 安放 上 左
  123. if(judge()) { ans = min(ans,num) ; break ; }
  124. work(v[j].first,v[j].second,0,3,0,1) ; //清除 上 左 / 安放 上 右
  125. }
  126. }
  127. }
  128. printf("%d\n",ans==INF ? -1 : ans) ;
  129. }
  130. return 0 ;
  131. }


 

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

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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