记录编号 105718 评测结果 AAAAAAAAAA
题目名称 [POJ 2841] 航海游戏 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 2.671 s
提交时间 2014-06-12 10:20:01 内存使用 5.47 MiB
显示代码纯文本
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<deque>
  6. using namespace std;
  7. const int SIZEN=1010,INF=0x7fffffff/2;
  8. int N,M;//N行M列
  9. char board[SIZEN][SIZEN]={0};
  10. int f[SIZEN][2][SIZEN]={0};
  11. int T[2][SIZEN]={0},a[SIZEN]={0};
  12. char line[SIZEN];
  13. int sa[SIZEN]={0},sp[SIZEN]={0};
  14. int wheel[SIZEN]={0};
  15. void reverse(int *s){//翻转s[1]~s[M]
  16. int i=1,j=M;
  17. while(i<j){
  18. swap(s[i],s[j]);
  19. i++,j--;
  20. }
  21. }
  22. void reverse(char *s){//翻转s[1]~s[M]
  23. int i=1,j=M;
  24. while(i<j){
  25. swap(s[i],s[j]);
  26. i++,j--;
  27. }
  28. }
  29. int cost(int k,bool flag,int j){
  30. return T[flag][k]+((j-k+1)*(j-k))/2+sp[j]-sp[k]-k*(sa[j]-sa[k]);
  31. }
  32. class POINT{
  33. public:
  34. int x,y;//x其实就是下标
  35. bool flag;//命运之轮次数奇偶性
  36. void print(void){printf("(%intd %intd %d)",x,y,flag);}
  37. };
  38. int calc_Y(int k,int flag){
  39. return k*k-2*sp[k]+2*k*sa[k]+2*T[flag][k];
  40. }
  41. bool check(POINT a,POINT b,int k){//ab斜率是否大于k,其中b的横坐标一定比a大
  42. return (b.y-a.y)>k*(b.x-a.x);
  43. }
  44. class CONQUEUE{//斜率优化维护凸包,凸包是下凸的
  45. public:
  46. deque<POINT> Q;
  47. void push(int x,int flag,int k){//将下标为x纳入考虑,并用斜率k维护凸包
  48. int y=calc_Y(x,flag);
  49. POINT temp;
  50. temp.x=x,temp.flag=flag,temp.y=y;
  51. while(Q.size()&&!check(Q.back(),temp,k)) Q.pop_back();
  52. Q.push_back(temp);
  53. }
  54. void maintain_front(int k){
  55. while(Q.size()>=2&&!check(Q[0],Q[1],k)) Q.pop_front();
  56. }
  57. int frontcost(int j){//刚才已经维护过了,计算走到j的最优解
  58. if(Q.empty()) return -1;
  59. return cost(Q.front().x,Q.front().flag,j);
  60. }
  61. void clear(void){
  62. Q.clear();
  63. }
  64. };
  65. CONQUEUE Q[2];
  66. void DP_line(int f[2][SIZEN]){//这个函数需要指定line,T,a
  67. Q[0].clear(),Q[1].clear();
  68. memset(f,-1,sizeof(int)*2*SIZEN);
  69. for(int j=1;j<=M;j++){
  70. sa[j]=sa[j-1]+a[j];
  71. sp[j]=sp[j-1]+a[j]*j;
  72. wheel[j]=wheel[j-1]+(line[j]=='F');
  73. if(line[j]=='O'){//这是一块石头
  74. Q[0].clear(),Q[1].clear();
  75. continue;
  76. }
  77. int k=2*j+1+2*sa[j];//斜率
  78. for(int t=0;t<=1;t++){
  79. bool flag=t^(wheel[j-1]&1);
  80. if(T[t][j]==-1) continue;
  81. Q[flag].push(j,t,k);//这里新加入决策
  82. }
  83. Q[0].maintain_front(k),Q[1].maintain_front(k);
  84. for(int t=0;t<=1;t++){
  85. bool flag=t^(wheel[j]&1);
  86. f[t][j]=Q[flag].frontcost(j);
  87. }
  88. }
  89. }
  90. void prepare_line(int i){
  91. memcpy(line,board[i],sizeof(line));
  92. memset(T[0],-1,sizeof(T[0])),memset(T[1],-1,sizeof(T[1]));
  93. for(int t=0;t<=1;t++){
  94. for(int j=1;j<=M;j++){
  95. if(f[i+1][t][j]==-1) continue;
  96. if(line[j]=='O') continue;
  97. T[t][j]=f[i+1][t][j]+1;
  98. if(line[j]=='B') T[t][j]--;
  99. else if(line[j]=='S') T[t][j]++;
  100. }
  101. }
  102. for(int j=1;j<=M;j++){
  103. if(line[j]=='B') a[j]=-1;
  104. else if(line[j]=='S') a[j]=1;
  105. else a[j]=0;
  106. }
  107. }
  108. int g1[2][SIZEN]={0},g2[2][SIZEN]={0};
  109. int DPmin(int a,int b){
  110. if(a==-1) return b;
  111. if(b==-1) return a;
  112. return min(a,b);
  113. }
  114. void DP(void){
  115. for(int i=1;i<=M;i++) if(board[N][i]=='H') f[N][0][i]=0;
  116. for(int i=N-1;i>=2;i--){
  117. prepare_line(i);
  118. DP_line(g1);
  119. reverse(line),reverse(T[0]),reverse(T[1]),reverse(a);
  120. DP_line(g2);
  121. for(int j=1;j<=M;j++){
  122. for(int t=0;t<=1;t++){
  123. f[i][t][j]=DPmin(g1[t][j],g2[t][M+1-j]);
  124. }
  125. }
  126. }
  127. int ans=INF;
  128. for(int i=1;i<=M;i++){
  129. if(board[1][i]!='H') continue;
  130. if(f[2][1][i]==-1) continue;
  131. ans=min(ans,f[2][1][i]+1);
  132. }
  133. if(ans==INF) printf("No solution\n");
  134. else printf("%d\n",ans);
  135. }
  136. void read(void){
  137. memset(f,-1,sizeof(f));
  138. scanf("%d%d",&N,&M);
  139. for(int i=1;i<=N;i++) scanf("%s",&board[i][1]);
  140. }
  141. int main(){
  142. freopen("navigationgame.in","r",stdin);
  143. freopen("navigationgame.out","w",stdout);
  144. read();
  145. DP();
  146. return 0;
  147. }