51nod 1580 铺管道(折线问题)
来源:互联网 发布:老婆胸大的体验知乎 编辑:程序博客网 时间:2024/05/20 20:04
现在要在一个城市中铺设管道。
这个城市是由 n×m 小方格组成的。每一个小方格要么是空的(管道可以铺设在上面),要么是实的(管道不能铺在上面)。空的用’.’表示,实的用’#’表示。
管道铺设的规则如下:
· 整条管道是形状是宽度为1的折线;
· 管道只能铺设在空的格子上面;
· 管道的两个端点只能在边缘上,但是不能在角上;
· 管道最多只能转两个弯(90度);
· 在管道上的格子有且只能有两个是在边缘上的;
· 如果管道是一条直线,那么他的两个端点必须是落在不同的边上;
· 对于管道上的非边缘格子,每一个格子会有且仅有两个相邻的其它格子在管道上;
· 对于管道上处于边缘的格子,仅有一个相邻的格子处于管道上。
下面有一些合法的管道铺设例子:
下面是一些非法铺设的例子:
这些例子中管道用’*’表示。
现在给定城市的地图,请计算一下有多少种方法铺设管道。
样例解释:
在这个样例中,有三种方法铺设管道(管道用'*'表示)。
单组测试数据。第一行有两个整数 n,m (2≤n,m≤2000),表示城市地图的高和宽。接下来n行,每一行有m个字母,表示城市地图。如果字符是’.’,表示该格子是空的,管道可以铺设。如果字符是’#’,表示该格子是实的,管道不能铺设。
输出一个整数,表示管道铺设方案的种数。
样例输入13 3.....#...
样例输出13
允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章
题意很繁琐,问题就是求满足题目描述的管道数量。一开始想的广搜,果断超时。。但是好像cf不会超时啊。
后来查了发正解,发现问题可以转化为折线问题。我们可以把管道看做折线(其实没啥区别)
然后满足题意的折线无非4种。。借鉴一个大佬的图。。
图片来源:http://www.cnblogs.com/dancer16/p/7351701.html
然后我们就可以按照题目要求查找满足要求的直线了,为哦了避免重复计算,所以考虑先计算纵向的
然后折叠矩阵,交换位置(可能说的不是很对,词穷了),中间的细节很多,敲了半天一直wa。
然后借鉴了一位大佬的代码:http://blog.csdn.net/f_zyj/article/details/72909671,才避免了许多重复计算。很巧妙
#include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<string> #include<math.h> #include<time.h> #include<stdio.h> #include<iostream> #include<string.h> #include<stdlib.h> #include<algorithm> #include<functional> using namespace std;typedef long long ll;#define inf 1000000000 #define mod 1000000007 #define maxn 2005 #define PI 3.1415926 #define lowbit(x) (x&-x) #define eps 1e-9char s[maxn];bool a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], d[maxn][maxn];ll ans;void solve(int n, int m, int flag){int i, j, tmp;memset(c, 0, sizeof(c));memset(d, 0, sizeof(d));for (i = 1;i <= n;i++)for (j = 1;j <= m;j++)c[i][j] = c[i - 1][j] | a[i][j];for (i = n;i > 0;i--)for (j = 1;j <= m;j++)d[i][j] = d[i + 1][j] | a[i][j];for (i = 2;i < n;i++){tmp = 0;c[i][1] = d[i][1] = 1;//防止把第一列给算进去。if (!a[i][1] && flag)//为避免重复,只需算一次下...左...tmp = 1;for (j = 2;j < m;j++){if (a[i][j]){tmp = 0;continue;}ans += ((!c[i][j]) + (!d[i][j]))*tmp;ans += ((!c[i][j] && !d[i][j - 1]) + (!c[i][j - 1] && !d[i][j]));tmp += (!c[i][j - 1]) + (!d[i][j - 1]);//之后累加能组成下...右...上和上...右...下等折线}if (!a[i][m] && flag)//加上从前边任何一列开始为下...右...和上...右...的折线ans += tmp + (!c[i][m - 1]) + (!d[i][m - 1]);//以及左右直达的直线}if (flag)//在算其他类型折线的同事横向直线顺带求出了,故直线只用再求一次{for (i = 2;i < m;i++)ans += (!c[n][i]);}}int main(void){int n, m, i, j;scanf("%d%d", &n, &m);for (i = 1;i <= n;i++){scanf("%s", s + 1);for (j = 1;j <= m;j++)a[i][j] = s[j] == '#';}solve(n, m, 1);for (i = 1;i <= n;i++)for (j = 1;j <= m;j++)b[j][i] = a[i][j];memset(a, 0, sizeof(a));for (i = 1;i <= m;i++)for (j = 1;j <= n;j++)a[i][j] = b[i][j];solve(m, n, 0);printf("%lld\n", ans);return 0;}
- 51nod 1580 铺管道(折线问题)
- 51Nod-1580-铺管道
- 51nod 1580 铺管道
- 51nod 1608 管道安装
- 51Nod 1608 管道安装
- 51nod 活动安排问题 (贪心)
- 51nod 1605 棋盘问题(博弈)
- 51Nod-棋子游戏(博弈问题)
- 经典问题:流水线调度(51nod)
- 51Nod 活动安排问题(贪心)
- 51nod 1605 棋盘问题(博弈)
- 多重背包问题(51Nod 1086)
- 51nod 1416两点问题(DFS)
- 51nod 独木舟问题
- 51nod-独木舟问题
- 51nod 迷宫问题
- 51nod独木舟问题
- 51nod大鱼吃小鱼问题
- try...catch...finally对IO流异常进行处理
- Java——泛型
- 面试OR笔试38——游历城市
- ajaxfileUpload插件错误
- 练习4: 求一个n阶方阵对角线元素之和。
- 51nod 1580 铺管道(折线问题)
- Gym
- 进程间的通信方式
- 调试FFmpeg
- 引用类型总结——ECMAScript
- 九度[1103]-二次方程计算器
- LeetCode 121. Best Time to Buy and Sell Stock
- 练习5: 输入一个一维数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。
- Python:AttributeError: ‘module’ object has no attribute ‘ArgumentParser’