记录编号 |
105718 |
评测结果 |
AAAAAAAAAA |
题目名称 |
[POJ 2841] 航海游戏 |
最终得分 |
100 |
用户昵称 |
cstdio |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
2.671 s |
提交时间 |
2014-06-12 10:20:01 |
内存使用 |
5.47 MiB |
显示代码纯文本
- #include<iostream>
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- #include<deque>
- using namespace std;
- const int SIZEN=1010,INF=0x7fffffff/2;
- int N,M;//N行M列
- char board[SIZEN][SIZEN]={0};
- int f[SIZEN][2][SIZEN]={0};
- int T[2][SIZEN]={0},a[SIZEN]={0};
- char line[SIZEN];
- int sa[SIZEN]={0},sp[SIZEN]={0};
- int wheel[SIZEN]={0};
- void reverse(int *s){//翻转s[1]~s[M]
- int i=1,j=M;
- while(i<j){
- swap(s[i],s[j]);
- i++,j--;
- }
- }
- void reverse(char *s){//翻转s[1]~s[M]
- int i=1,j=M;
- while(i<j){
- swap(s[i],s[j]);
- i++,j--;
- }
- }
- int cost(int k,bool flag,int j){
- return T[flag][k]+((j-k+1)*(j-k))/2+sp[j]-sp[k]-k*(sa[j]-sa[k]);
- }
- class POINT{
- public:
- int x,y;//x其实就是下标
- bool flag;//命运之轮次数奇偶性
- void print(void){printf("(%intd %intd %d)",x,y,flag);}
- };
- int calc_Y(int k,int flag){
- return k*k-2*sp[k]+2*k*sa[k]+2*T[flag][k];
- }
- bool check(POINT a,POINT b,int k){//ab斜率是否大于k,其中b的横坐标一定比a大
- return (b.y-a.y)>k*(b.x-a.x);
- }
- class CONQUEUE{//斜率优化维护凸包,凸包是下凸的
- public:
- deque<POINT> Q;
- void push(int x,int flag,int k){//将下标为x纳入考虑,并用斜率k维护凸包
- int y=calc_Y(x,flag);
- POINT temp;
- temp.x=x,temp.flag=flag,temp.y=y;
- while(Q.size()&&!check(Q.back(),temp,k)) Q.pop_back();
- Q.push_back(temp);
- }
- void maintain_front(int k){
- while(Q.size()>=2&&!check(Q[0],Q[1],k)) Q.pop_front();
- }
- int frontcost(int j){//刚才已经维护过了,计算走到j的最优解
- if(Q.empty()) return -1;
- return cost(Q.front().x,Q.front().flag,j);
- }
- void clear(void){
- Q.clear();
- }
- };
- CONQUEUE Q[2];
- void DP_line(int f[2][SIZEN]){//这个函数需要指定line,T,a
- Q[0].clear(),Q[1].clear();
- memset(f,-1,sizeof(int)*2*SIZEN);
- for(int j=1;j<=M;j++){
- sa[j]=sa[j-1]+a[j];
- sp[j]=sp[j-1]+a[j]*j;
- wheel[j]=wheel[j-1]+(line[j]=='F');
- if(line[j]=='O'){//这是一块石头
- Q[0].clear(),Q[1].clear();
- continue;
- }
- int k=2*j+1+2*sa[j];//斜率
- for(int t=0;t<=1;t++){
- bool flag=t^(wheel[j-1]&1);
- if(T[t][j]==-1) continue;
- Q[flag].push(j,t,k);//这里新加入决策
- }
- Q[0].maintain_front(k),Q[1].maintain_front(k);
- for(int t=0;t<=1;t++){
- bool flag=t^(wheel[j]&1);
- f[t][j]=Q[flag].frontcost(j);
- }
- }
- }
- void prepare_line(int i){
- memcpy(line,board[i],sizeof(line));
- memset(T[0],-1,sizeof(T[0])),memset(T[1],-1,sizeof(T[1]));
- for(int t=0;t<=1;t++){
- for(int j=1;j<=M;j++){
- if(f[i+1][t][j]==-1) continue;
- if(line[j]=='O') continue;
- T[t][j]=f[i+1][t][j]+1;
- if(line[j]=='B') T[t][j]--;
- else if(line[j]=='S') T[t][j]++;
- }
- }
- for(int j=1;j<=M;j++){
- if(line[j]=='B') a[j]=-1;
- else if(line[j]=='S') a[j]=1;
- else a[j]=0;
- }
- }
- int g1[2][SIZEN]={0},g2[2][SIZEN]={0};
- int DPmin(int a,int b){
- if(a==-1) return b;
- if(b==-1) return a;
- return min(a,b);
- }
- void DP(void){
- for(int i=1;i<=M;i++) if(board[N][i]=='H') f[N][0][i]=0;
- for(int i=N-1;i>=2;i--){
- prepare_line(i);
- DP_line(g1);
- reverse(line),reverse(T[0]),reverse(T[1]),reverse(a);
- DP_line(g2);
- for(int j=1;j<=M;j++){
- for(int t=0;t<=1;t++){
- f[i][t][j]=DPmin(g1[t][j],g2[t][M+1-j]);
- }
- }
- }
- int ans=INF;
- for(int i=1;i<=M;i++){
- if(board[1][i]!='H') continue;
- if(f[2][1][i]==-1) continue;
- ans=min(ans,f[2][1][i]+1);
- }
- if(ans==INF) printf("No solution\n");
- else printf("%d\n",ans);
- }
- void read(void){
- memset(f,-1,sizeof(f));
- scanf("%d%d",&N,&M);
- for(int i=1;i<=N;i++) scanf("%s",&board[i][1]);
- }
- int main(){
- freopen("navigationgame.in","r",stdin);
- freopen("navigationgame.out","w",stdout);
- read();
- DP();
- return 0;
- }