题目大意:
  一个$n\times m(n,m\leq400)$的网格图中,每个格子上放了两个三明治,摆放的方式分为'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)$。
  具体实现上,可以用$0\sim3$来表示不同的方向。若摆放方式为'N'的格子,一个直角边的方向为$d$,则另一个直角边的方向为$d\oplus3$;若摆放方式为'Z'的格子,一个直角边的方向为$d$,则另一个直角边的方向为$d\oplus1$。搜索时的一系列分类讨论可以通过简单的位运算实现。

 #include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
inline bool getblock() {
register char ch;
while(!isalpha(ch=getchar()));
return ch=='N';
}
const int N=,inf=0x7fffffff;
const int dx[]={,-,,},dy[]={-,,,};
bool a[N][N];
int n,m,f[N][N],ans[N][N],tmp,flag;
inline bool check(const int &x,const int &y) {
return x>=&&x<n&&y>=&&y<m;
}
void dfs(const int &x,const int &y,const int &d) {
if(!~f[x][y]) {
flag=true;
return;
}
if(f[x][y]) return;
tmp+=;
f[x][y]=-;
const int p=a[x][y]?:;
if(check(x-dx[d],y-dy[d])) dfs(x-dx[d],y-dy[d],d);
if(check(x-dx[d^p],y-dy[d^p])) dfs(x-dx[d^p],y-dy[d^p],d^p);
f[x][y]=;
}
int main() {
for(register int T=getint();T;T--) {
n=getint(),m=getint();
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
a[i][j]=getblock();
}
}
for(register int i=;i<n;i++) {
flag=tmp=;
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
f[i][j]=;
}
}
for(register int j=;j<m;j++) {
if(!flag) dfs(i,j,);
ans[i][j]=flag?inf:tmp;
}
flag=tmp=;
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
f[i][j]=;
}
}
for(register int j=m-;~j;j--) {
if(!flag) dfs(i,j,);
ans[i][j]=std::min(ans[i][j],flag?inf:tmp);
}
}
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
printf("%d%c",ans[i][j]!=inf?ans[i][j]:-," \n"[j==m-]);
}
}
}
return ;
}

最新文章

  1. .NET 垃圾回收与内存泄漏
  2. linux shell 读取for循环中出现难处理的数据之单引号错误实例
  3. Ubuntu 固态硬盘 4K对齐及启用 Trim,及其验证方法
  4. 服务器设置Apache对htaccess支持
  5. &#167;12 循环101-while循环
  6. readmine项目管理和缺陷跟踪工具
  7. 前台任意页面调用自定义字段选项 box 单选 多选方法及查询
  8. ORA-14400: inserted partition key does not map to any partition
  9. 数据结构与算法分析 3.4&amp;3.5 — 链表的交与并算法
  10. [ZJOI2005]九数码游戏
  11. 201904Online Human Action Recognition Based on Incremental Learning of Weighted Covariance Descriptors
  12. LongAdder,AtomicIntegerFieldUpdater深入研究
  13. R 分组计算描述性统计量
  14. BZOJ1103 [POI2007]大都市
  15. Maven插件的简介,安装及在eclipse中配置
  16. mr中间结果优化
  17. 47. Permutations II (全排列有重复的元素)
  18. 在Ubuntu14.4(32位)中配置I.MX6的QT编译环境
  19. python 线程/进程模块
  20. 找不到 libgtk-x11-2.0.so.0

热门文章

  1. Windows7中如何让python2和python3共存并使用pip
  2. 1099 Build A Binary Search Tree (30 分)(查找二叉树)
  3. 1086 Tree Traversals Again (25 分)(二叉树的遍历)
  4. java作业 2017.10.14
  5. 在LinkedIn的 Kafka 生态系统
  6. Codeforces Round #386 (Div. 2) 746F(set的运用)
  7. NOIP2017年11月9日赛前模拟
  8. bzoj1396&amp;&amp;2865 识别子串 后缀自动机+线段树
  9. Android横竖屏总结(转)
  10. jQuery操作下拉列表以及单选多选框