Dynamic Programming 练习(题源 hdu 1466, 计算直线的交点数)

有空练了练动态规划,用来练习的题目是航电的1466题,链接如下

 

http://acm.hdu.edu.cn/showproblem.php?pid=1466

这道题目注意是求交点的方案数,也就是说,给定直线数,列出这些直线各种相交的情况下对应的交点数。

首先n条直线,排列组合下,最多能有C(n,2)=n(n-1)/2个交点。

 

子问题划分:

m条直线,划分为两部分,一部分为A,A中所有线相互平行,剩下的部分为B,假设B里面有r条直线,相交情况未知,可能部分相交,部分平行,但是B中绝没有和A平行的线了。

 这样m条直线的交点数 = (m-r)条平行线与r条直线交叉的交点数 + r条直线的交点数

(1)注意到(m-r)条平行线和r条直线的交点数很好算,因为这里不考虑r条直线内部的交点了,所以所有的交点必然落在m-r条平行线上,又因为r条直线没有一条和m-r条直线平行了,所以对于m-r条直线中的每一条,它都和r条直线相交,故而共有(m-r)*r个交点。在m和r确定的情况下,此值确定。

(2)r条直线的交点数,r条直线的交点数有不止一种方案,但是注意到这些交点数的计算方式和求m条直线交点数一样,于是就是一个子问题,递归就可以写出了。

递归函数定义:

定义int func(int lines, int nodes)

lines表示此时的直线数,nodes表示交点数,func的返回值为1时,表示这些直线存在交点数为nodes的情况,反之为0。

由于递归重复较多,用rec[m][n]记忆func(m,n)的值避免重复运算。

如何计算func的值?如果m条直线存在n个交点,由于 n = (m-r)*r + r条直线的交点数

那么 r条直线的交点数 = n -(m-r)*r,也就是说 r 条直线也存在交点数为 n -(m-r)*r 的情况,也就是说func(r,n-(m-r)*r)==1

 

这样func(lines, nodes)的pseudo code表示如下:

 

func(lines, nodes)

{

 

 if rec[lines][nodes]已经赋值了

  return rec[lines][nodes]

 for(r = lines; r > 0;r--){

  func(i,nodes - (lines-r)*r);

  if 这些func返回值有一个>0

    return 1;

    rec[lines][nodes] = 1;

  else

    return 0;

 

    rec[lines][nodes] = 0;

 

 }

}

 

代码如下(C++实现):

 1 #include <memory.h>
 2 #include <iostream>
 3 using namespace std;
 4 
 5 int rec[21][191];
 6 
 7 int func(int lines, int nodes){
 8     if (rec[lines][nodes] > -1)
 9         return rec[lines][nodes];
10     int r = lines-1, sum = 0;
11     for(;r > 0;r--){
12         int n = nodes - (lines-r)*r;
13         if (n >= 0) sum += func(r,n);
14     }
15     rec[lines][nodes] = (sum > 0 ? 1 : 0);
16     return rec[lines][nodes];
17 }
18 
19 int main(){
20     memset(rec, -1sizeof(rec));
21     int i = 1, j = 0;
22     for(i = 0;i < 21;i++)
23         rec[i][0] = 1;
24     for (i = 1;i < 191;i++)
25         rec[1][i] = 0;
26     int numLines = 0;
27     while (cin >> numLines){
28         cout << "0";
29         for(j = 1;j <= numLines*(numLines-1)/2;j++)
30             if(func(numLines,j) > 0)
31                 cout << " " << j;
32         cout << endl;
33     }
34     return 0;
35 }

 

posted on 2012-03-10 21:02  Felix Fang  阅读(688)  评论(0编辑  收藏  举报

导航