dp问题是日常生活乃至编程竞赛中经常遇到的一类有意义的问题,他的一大特点就是:记录下小规模数据的最优解,然后将其应用于大规模数据的计算当中。但是,在这儿,最难思考的就是所谓的转移方程。如何通过合适的变化得到当前的状态,是动态规划问题的核心。可以说,得到了相应的状态转移方程,问题便相应而解。下面,就看一道杭电的简单动态规划来看具体的状态转移。
题目的网址:http://acm.hdu.edu.cn/showproblem.php?pid=1466
题目的描述十分简单,就是输出n条直线相交的交点的所有可能情况。但是,如果给出一个n强行求的话,不仅没有合适的算法,而且程序会十分耗时。所以我们利用动态规划的问题来进行求解。但是,如何进行思考呢?
我们知道,交点的个数与这些直线相交的情况有关。我们将直线分为两堆,一堆是这些直线中最大的平行直线序列。而另一堆直线中,可能会有相互平行的直线,也有可能不存在相互平行的直线,所以我们设他们的交点数为j,那么这n条直线的总交点数就是r(n-r)+j(r为第一堆中直线的数目)。而n条直线最多会有n*(n-1)/2个交点,这样循环的上下界便确定了。问题便相应解决。
代码;
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n;
int r;
int i, j;
int dp[21][191];
memset(dp, 0, sizeof(dp));
for (i = 0; i <= 20; i++)
{
dp[i][0] = 1;
for (r = 0; r <= i; r++)
{
for (j = 0; j <= 190; j++)
{
if (dp[r][j] == 1)
{
dp[i][(i - r)*r + j] = 1;
}
}
}
}
while (scanf("%d", &n) != EOF)
{
for (j = 0; j <= n*(n - 1) / 2; j++)
{
if (dp[n][j] == 1)
{
if (j != 0)
cout << " ";
cout << j;
}
}
cout << endl;
}
return 0;
}