HDU1466 计算直线的交点数

最近在看一些动规的题目,看到这个题首先想到的是将n条直线分开,分成两部分。第一部分有(n-i)条,两两平行,第二部分有i条,与第一部分不平行。于是,总的交点数 = 第一部分的交点数 + 第二部分的交点数 + 两部分之间的交点数。第一部分互相平行,交点数为0;第二部分为原问题的一个子问题;两部分之间的交点数等于两部分的直线条数的乘积。用m[k]来表示k条直线的交点数,于是 m[n] = m[i]+i*(n-i)   (0<=i<=n-1,假设 i 已知)。于是问题规模变小了。

考虑到n条直线的交点数最多可以取 n(n-1)/2,题目中n最大取20,即交点数最多为190,定义二维数组m[21][1000],m[i][j] 表示 i 条直线可以产生的第 j 种不同的交点数。一维数组n[21],n[k]表示k条直线产生的最多交点数。

先计算各个子问题,即从m[0]开始,逐次计算m[i],直到m[n],为第一层循环。

对于每个k,m[k] = m[i]+i*(k-i),0<=i<=k-1,依次考虑 i 的不同取值,计算出的不同m[k]利用插入排序方法存入 m[k][ ]中,为第二层循环。

对于每个m[i],有n[i]种不同取值,为第三层循环。 

算法实现如下:


#include <iostream>
#include <cstring>

using namespace std;

int m[21][1000];
int n[21];

void insert_sort(int a[],int &n,int x)
{
    int i,j;
    if(x>a[n-1])
    {
        a[n]=x;
        n++;
    }
    else if(x==a[n-1])
        return;
    else
    {
        for(i=0;i<n-1;i++)
        {
            if(x==a[i]) return;
            if(x>a[i] && x<a[i+1])
            {
                for(j=n-1;j>=i+1;j--)
                    a[j+1]=a[j];
                a[i+1]=x;
                n++;
            }
        }
    }
}
int main()
{
    int i,j,k,t,q;
    memset(m,0,sizeof(m));
    memset(n,0,sizeof(n));
    for(i=0;i<=20;i++)
    {
        m[i][0]=0;
        n[i]=1;
    }
    for(i=1;i<=20;i++)
    {
        for(j=0;j<=i-1;j++)
        {
            q=(i-j)*j;
            for(k=0;k<n[j];k++)
            {
                insert_sort(m[i],n[i],m[j][k]+q);
            }
        }
    }
    while(cin>>t)
    {
        cout <<m[t][0];
        for(i=1;i<n[t];i++)
            cout <<" " <<m[t][i];
        cout <<endl;
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值