zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    不同品牌交换机设置telnet方法
    Oracle 11G RAC For Windows 2008 R2部署手册(亲测,成功实施多次)
    oracle 11g ADG实施手册(亲测,已成功部署多次)
    如何正确的使用uwsgi
    debian小巧好看的桌面
    zsh中home键失灵问题
    C#_Markov_心得感想
    NLP—WordNet——词与词之间的最小距离
    这不算爬虫吧?!
    Table-Driven Design 表驱动设计
  • 原文地址:https://www.cnblogs.com/skylee03/p/8413400.html
Copyright © 2011-2022 走看看