HDU1466 计算直线的交点数

来源:互联网 发布:汽车报价软件哪个好 编辑:程序博客网 时间:2024/05/22 12:27

最近在看一些动规的题目,看到这个题首先想到的是将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
原创粉丝点击