• 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 }
  • 相关阅读:
    四则运算题目的程序
    Github注册账户过程
    目前流行的源程序版本管理软件和项目管理软件都有哪些?各有什么优缺点?
    学习进度总结
    学习进度总结
    7月29 日实习日志及总结
    7月28日实习日志
    7月27实习日志
    7月26日实习日志
    7月25日实习日志
  • 原文地址:https://www.cnblogs.com/felixfang/p/2389493.html
Copyright © 2020-2023  润新知