您的位置:首页 > 其它

hdu1466计算直线的交点数

2016-11-10 18:33 218 查看
这道题是从HDU课件上看到的,而且是DP的课件。

推导过程来自PPT:

当n = 20 时, 最大的交点数 = 1 + 2 + ... + (n - 1) = n * (n - 1) / 2 = 190

很容易看出前四个答案  

n = 0    0

n = 1    0

n = 2    0 1

n = 3    0 2 3 (解释一下: 0是三条直线平行的情况,2是两条直线平行的情况,3是每条之间都不平行于其他直线.)

现在我们把直线分为两组, 一组里面都是平行线a个,一组名字叫做自由线b个,那么 n = a + b,那么答案就是 ans = a组的交点个数+ a个平行线和b个自由线的交点个数 + b组交点个数

现在推导n = 4的情况 

(1) 考虑第四条线和三条线平行,那么平行线组里面有4条线,自由线组里面0条线,那么 ans =0 +  (4 - 0) * 0 + 0 = 0;

(2)考虑第四条线和两条线平行,那么平行线组里面有3条线,自由线组里面1条线,那么ans =0 +  (4 - 1) * 1 + 0 = 3;

(3)考虑第四条线和一条线平行,那么平行线组里面有2条线,自由线组里面2条线,这是自由线组里面有2种情况(参考n = 2时候的情况)

           情况1:自由线组里面的直线是平行的 ,所以ans = 0 + (4 - 2) * 2 + 0 = 4

           情况2:自由线组里面的直线是相交的,所以ans = 0 + (4 - 2) * 2 + 1 = 5

(4)考虑第四条线与其他线都不平行,那么平行线组里面有1条线,自由线组里面有3条线,这时候自由线组里面有3种情况(参考n = 3的情况)

          情况1:自由线组里面的直线都是平行的,所以ans = 0 + (4 - 3) * 3 + 0 = 3;

          情况2: 自由线组里面有两条直线是平行的,所以ans = 0 + (4 - 3) * 3 + 2 = 5;

          情况3:自由线组里面没有平行的线,所以ans = 0 + (4 - 3) * 3 + 3 = 6;

综上考虑,n = 4的时候有0 3 4 5 6 ,这5种情况的交点数。

我们用f[21][191] 数组来记录所有的情况,如果f[i][j] == 1,说明有i条线的时候,有j个交点。

下面推广到有m条线的时候

(1) 第m条线和m - 1条线平行,那么平行线里面有m条线,自由线组里面有0条线,那么 ans = 0 + (m - 0) * 0 + 0 = 0

(2)第m条线和m - 2条线平行,那么平行线里面有m - 1条线,自由线组里面有1条线,那么ans = 0 + (m - 1) * 1 + 0 = m - 1

....

(r)第m条线和m - r条线平行,那么平行线里面有m - r + 1条线,自由线组里面有r - 1条线,这里分成r - 1 个情况

                  那么ans = 0 + [m - (r - 1)] * (r - 1) + [n = r - 1时候的交点方案]

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int f[30][200],n,ans[30];
void init(){
memset(f,0,sizeof f);
for(int i = 0;i <= 20;++i)
f[i][0] = 1;
for(int i = 1;i <= 20;++i)
{
for(int j = 1;j < i;++j)
{
for(int k = 0;k < 191;++k)
{
if(f[j][k])
f[i][(i - j) * j + k] = 1;
}
}
}
}
int main(){
init();
while(~scanf("%d",&n)){
printf("0");
for(int i = 1;i <= 190;++i)
if(f
[i]) printf(" %d",i);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 DP 递推