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 }

 

转载于:https://www.cnblogs.com/felixfang/archive/2012/03/10/2389493.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值