1393 - Highways 计数问题
来源:互联网 发布:c51单片机计算器 编辑:程序博客网 时间:2024/05/29 07:10
Hackerland is a happy democratic country with m×n cities, arranged in a rectangular m by ngrid and connected by m roads in the east-west direction and n roads in the north-south direction. By public demand, this orthogonal road system is to be supplemented by a system of highways in sucha way that there will be a direct connection between any pair of cities. Each highway is a straight line going through two or more cities. If two cities lie on the same highway, then they are directly connected.If two cities are in the same row or column, then they are already connected by the existing orthogonal road system (each east-west road connects all the m cities in that row and each north-south road connects all the n cities in that column), thus no new highway is needed to connect them. Your task is to count the number of highway that has to be built (a highway that goes through several cities on a straight line is counted as a single highway).
Input
The input contains several blocks of test cases. Each test case consists of a single line containing two integers 1n , m300 , specifying the number of cities. The input is terminated by a test case with n = m = 0 .
Output
For each test case, output one line containing a single integer, the number of highways that must be built.
Sample Input
2 43 30 0
Sample Output
1214
本题是思想挺难的题目,抽象思维要求挺高的。
使用动态规划法,首先要弄明白如何记录数据,并且明白记录的数据代表什么意义,否则是理解不了的。
网上解析这道题的本来就不多,也许太难理解了,而解析的博客,我都没看明白,不知其所以言,有些是解析太简单了,也许作者是那样理解的,但是表达出来别人又没法理解了;
这里也只是给出自己的理解,也许别人不一定能理解我为什么这样理解的。不过给出图,详细说明一下,希望我可以说清楚。
作者 靖心:http://blog.csdn.net/kenden23/article/details/29185889
这里需要使用双重动态规划法了,首先定义第一个表tbl
这个表的数值,例如tbl[i][j]代表,从第一个点[1][1]到[i][j]点组成的(i-1) * (j-1)个方格,从点[1][1]出发想象发出射线到边界上所有点的总数。
如下图是i = 2, j = 2的时候有3条射线
如下图:
这样计算好一个表,为什么要这样记录数据呢? 因为比如我们的长方形是由n*m格组成的,我们记录所有的方格组成的到边界的射线,就可以通过查表得到所有线段数了。
上图的3*3方格包含了2*2个方格的子长方形,可以通过查表tbl[2][2]得到这个子长方形的射线数。
记录这个数据是这句代码:
for (int i = 1; i < N; i++){for (int j = 1; j < N; j++){//tbl[i][j]代表从顶点1,1出发的射线到边界的数量tbl[i][j] = tbl[i-1][j] + tbl[i][j-1] - tbl[i-1][j-1]+ (GCD(i, j) == 1? 1 : 0);}}下标其实是记录方格数的,并非记录顶点数。
然后因为一个大的N*M个方格包含了所有的子方格,所以需要把这些子方格都包含进去,计算总数才算是结果。
for (int i = 1; i < N; i++){for (int j = 1; j < N; j++){//从小到大逆转使用的所谓inclusion-exclusion原理rs[i][j] = rs[i-1][j] + rs[i][j-1] - rs[i-1][j-1]+ tbl[i][j] - tbl[i>>1][j>>1];}}
最后,为什么需要-tbl[i>>1][j>>1]呢?因为大家可以按照上图画画射线,就知道tbl[i][j]的边界射线和tbl[i>>1][j>>1]射线重合了。
其实tbl是一个对角线对称的矩阵,可以只计算对角线上面的值*2优化。
要仔细观察,总结规律:
1 大的方格包含的子方格,可以通过填表防止重复计算,十分难抽象的一个思维
2 只需要记录边界射线就可以了,内射线和子方格的值一样
最后AC程序,挺快的,可以上UVa榜:
#include <cstdio>#include <cstdlib>#include <algorithm>#include <vector>using namespace std;class Highways1393{static const int N = 302;vector<vector<int> > tbl;vector<vector<int> > rs;int GCD(int a, int b){return b==0? a : GCD(b, a % b);}void makeTbl(){for (int i = 1; i < N; i++){for (int j = 1; j < N; j++){//tbl[i][j]代表从顶点1,1出发的射线到边界的数量tbl[i][j] = tbl[i-1][j] + tbl[i][j-1] - tbl[i-1][j-1]+ (GCD(i, j) == 1? 1 : 0);}}for (int i = 1; i < N; i++){for (int j = 1; j < N; j++){//从小到大逆转使用的所谓inclusion-exclusion原理rs[i][j] = rs[i-1][j] + rs[i][j-1] - rs[i-1][j-1]+ tbl[i][j] - tbl[i>>1][j>>1];}}}public:Highways1393() : tbl(N, vector<int>(N)), rs(N, vector<int>(N)){makeTbl();int r, c;while (scanf("%d %d", &r, &c) && (r != 0 && c != 0)){printf("%d\n", rs[r-1][c-1]<<1);}}};
- 1393 - Highways 计数问题
- LA 3720 Highways (计数问题)
- 1393 - Highways(问题抽象)(容斥原理计数)
- UVA 1393 - Highways (容斥原理计数)
- SPOJ104 Highways,生成树计数
- 生成树计数 spoj 104 highways
- UVALive 3720 Highways(组合计数、递推)
- SPOJ 104 Highways 最小生成树计数
- spoj104 Highways(生成树计数模板)
- SPOJ 104 Highways(生成树计数)
- UVALive 3720-Highways -组合计数+gcd
- SPOJ Highways(生成树计数)
- UVa:1393 Highways
- UVA 1393 - Highways
- UVA - 1393 Highways
- UVA 1393 - Highways
- uva 1393 Highways
- UVA 1393Highways
- Android项目为一个apk设置多个ICON图标和执行入口
- 关于java CopyOnWriteArrayList 性能测试
- Top Coder SRM 614 DIV 2
- iOS开发 切换听筒和扬声器
- .NET4.0新特性
- 1393 - Highways 计数问题
- struts2简单的回传ajax数据方法
- Java虚拟机的内存区域——《深入理解Java虚拟机》学习笔记(一)
- android详解博客
- LeetCode-Minimum Depth of Binary Tree
- string的相关操作
- LayoutInflater的使用
- 归并排序与插入排序-C++实现
- Servlet的线程安全