poj 1466 计算直线的交点数
http://acm.hdu.edu.cn/showproblem.php?pid=1466
一道dp好题,是我们学校Troy哥在他的动态规划的课件里面的一道习题。这题要求我们找出n条直线可以构成哪几种数量的交点。自己想的时候想到了用当前处理第i条共有j个交点来进行动态规划,是因为显然可以看出前i条直线构成j (0<=j<=(i-1)*i/2) 个交点是必定可以推出前i+1条直线构成j (0<=j<=(i+1)*i/2) 个交点的,但是这个递推关系就不是那么容易找到了。
见识面还是比较窄,迫于无奈找了一下题解,其中我看到一个这样的转移方程:
dp[i-r][j] --> dp[i][(i-r)*r+j] (1<=r<i)
(自己搞的,和原文的有出入,其他题解很多都是写dp[i][j]=(i-r)*r+dp[r][k])
对于这样的一个方程,我参照别人题解里面所说的,弄不懂...- - 于是我就yy了一下,得出我的见解...希望对初学者的理解有帮助。
实际上,由方程可以看到其实还有一个算是状态的辅助参数r。这个r的作用是十分的强大,可以将它理解为要在i-r条直线里加上一组r条的平行线,而且这组平行线和原来i-r条线都不平行,所以交上以后就会多出r*(i-r)个交点。如果dp[i-r][j]可取,那么dp[i][(i-r)*r+j]就是可取的了。这样,接下来就是体力劳动了。
我的代码:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 5 #define debug 0 6 7 int min2(int _a, int _b){return _a < _b ? _a : _b;} 8 int max2(int _a, int _b){return _a > _b ? _a : _b;} 9 10 bool dp[21][191]; 11 12 bool solve(){ 13 memset(dp, 0, sizeof(dp)); 14 for (int i = 0; i <= 20; i++){ 15 dp[i][0] = true; 16 } 17 for (int i = 2; i <= 20; i++){ 18 for (int j = 1; j < i; j++){ 19 for (int k = 0; k <= 190; k++){ 20 dp[i][k + j * (i - j)] |= dp[i - j][k]; 21 } 22 } 23 } 24 #if debug 25 for (int i = 1; i <= 6; i++){ 26 for (int j = 0; j < 20; j++){ 27 printf("%d", dp[i][j]); 28 } 29 puts(""); 30 } 31 #endif 32 33 return true; 34 } 35 36 int main(){ 37 int n; 38 39 solve(); 40 while (~scanf("%d", &n)){ 41 int i = 0, end = n * (n - 1) >> 1; 42 43 for (; i < end; i++){ 44 if (dp[n][i]) printf("%d ", i); 45 } 46 printf("%d\n", end); 47 } 48 49 return 0; 50 }
——written by Lyon