• [JOISC2016]サンドイッチ


    题目大意:
      一个$n imes m(n,mleq400)$的网格图中,每个格子上放了两个三明治,摆放的方式分为'N'和'Z'两种。一个三明治可以被拿走当且仅当与该三明治的两条直角边相邻的三明治均被拿走或与该三明治斜边相邻的三明治被拿走。问对于每个格子,想要拿走这个格子中的所有三明治至少需要先拿走多少三明治。

    思路:
      对于同一个格子,不难发现这一个格子中两个三明治接连被拿走一定是最优的。
      于是这题就和每个单独的三明治取走顺序没什么关系了,只和每个方格取走顺序及三明治的摆放方式有关。
      $O(n^2)$枚举每个格子$(x,y)$,假设它是因为$(x-1,y)$和$(x,y-1)$被取走后才被取走,我们可以$O(n^2)$DFS出最优情况下,取走每个格子之前一定要取走哪些格子。时间复杂度$O(n^4)$,bitset优化为$O(frac{n^4}{omega})$。
      不难发现,若$(x,y)$是因为$(x-1,y)$被取走才被取走的,$(x-1,y)$不可能因为$(x,y)$被取走才被取走。因此对于同一行的格子,我们可以让后面的DFS重复利用前面DFS出的信息。DFS是$O(n^2)$的,每一行要重新DFS,时间复杂度是$O(n^3)$。
      具体实现上,可以用$0sim3$来表示不同的方向。若摆放方式为'N'的格子,一个直角边的方向为$d$,则另一个直角边的方向为$doplus3$;若摆放方式为'Z'的格子,一个直角边的方向为$d$,则另一个直角边的方向为$doplus1$。搜索时的一系列分类讨论可以通过简单的位运算实现。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<algorithm>
     4 inline int getint() {
     5     register char ch;
     6     while(!isdigit(ch=getchar()));
     7     register int x=ch^'0';
     8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     9     return x;
    10 }
    11 inline bool getblock() {
    12     register char ch;
    13     while(!isalpha(ch=getchar()));
    14     return ch=='N';
    15 }
    16 const int N=400,inf=0x7fffffff;
    17 const int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
    18 bool a[N][N];
    19 int n,m,f[N][N],ans[N][N],tmp,flag;
    20 inline bool check(const int &x,const int &y) {
    21     return x>=0&&x<n&&y>=0&&y<m;
    22 }
    23 void dfs(const int &x,const int &y,const int &d) {
    24     if(!~f[x][y]) {
    25         flag=true;
    26         return;
    27     }
    28     if(f[x][y]) return;
    29     tmp+=2;
    30     f[x][y]=-1;
    31     const int p=a[x][y]?3:1;
    32     if(check(x-dx[d],y-dy[d])) dfs(x-dx[d],y-dy[d],d);
    33     if(check(x-dx[d^p],y-dy[d^p])) dfs(x-dx[d^p],y-dy[d^p],d^p);
    34     f[x][y]=1;
    35 }
    36 int main() {
    37     for(register int T=getint();T;T--) {
    38         n=getint(),m=getint();
    39         for(register int i=0;i<n;i++) {
    40             for(register int j=0;j<m;j++) {
    41                 a[i][j]=getblock();
    42             }
    43         }
    44         for(register int i=0;i<n;i++) {
    45             flag=tmp=0;
    46             for(register int i=0;i<n;i++) {
    47                 for(register int j=0;j<m;j++) {
    48                     f[i][j]=0;
    49                 }
    50             }
    51             for(register int j=0;j<m;j++) {
    52                 if(!flag) dfs(i,j,2);
    53                 ans[i][j]=flag?inf:tmp;
    54             }
    55             flag=tmp=0;
    56             for(register int i=0;i<n;i++) {
    57                 for(register int j=0;j<m;j++) {
    58                     f[i][j]=0;
    59                 }
    60             }
    61             for(register int j=m-1;~j;j--) {
    62                 if(!flag) dfs(i,j,0);
    63                 ans[i][j]=std::min(ans[i][j],flag?inf:tmp);
    64             }
    65         }
    66         for(register int i=0;i<n;i++) {
    67             for(register int j=0;j<m;j++) {
    68                 printf("%d%c",ans[i][j]!=inf?ans[i][j]:-1," 
    "[j==m-1]);
    69             }
    70         }
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    应用服务器安装
    datasnap的线程池
    压缩OLEVARIANT数据
    服务端日志记录
    提交主从表的多个已经修改的数据
    MySQL与PostgreSQL相比哪个更好?
    Vue入门常用指令详解
    Laravel模型事件的实现原理详解
    Git 遇到了 early EOF indexpack failed 问题
    Laravel 代码开发最佳实践
  • 原文地址:https://www.cnblogs.com/skylee03/p/8413400.html
Copyright © 2020-2023  润新知