【动态规划基础】二色马
Time Limit:1000MS Memory Limit:65536K
Description
一个农夫要把n只马分配到k个马房里,放置的规则是:第1 到 第pi只马放入第一个马房,第pi+1 到第pk只放入第二个马房,......,以此类推。此外对于每一个马房都有一个叫做“不高兴系数”,即白色马的数量*黑色马的数量。你的任务是合理地分配这n只马,使得它所有马房的“不高兴系数”和最小。
Input
从文件horses.in中读入数据,文件中第一行有 2 个整数: n ( 1 <= n <= 500 ) 和 k ( 1 <= k <= n)。接下来的n行有n个数。第 i 行为第 i 只马的颜色: 1 是黑色, 0 是白色。
Output
将结果输出到文件horses.out中,其结果为最小的“不高兴系数”的总和。
Sample Input
6 3
1
1
0
1
0
1
Sample Output
2
经典的区间动规。
用f[i][j]表示前i只马放到前j个马房的最小“不高兴系数”,则:
f[i][j]=min(f[i][j],f[k][j]+a[k+1][j])
其中a[i][j]表示将i到j匹马放到同一个马房的“不高兴系数”。
a[i][j]需要预处理出来,详见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[501][501];
int a[501][501];
int c[501];
int n,t;
int main()
{
scanf("%d%d",&n,&t);
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
for (int i=1;i<n;i++)
{
int l=0;
int r=0;
if (c[i]==1) l++; else r++;
for (int j=i+1;j<=n;j++)
{
if (c[j]==1)
l++;
else r++;
a[i][j]=l*r;
}
}
memset(f,0x7f7f,sizeof(f));
f[0][0]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=min(i,t);j++)
for (int k=0;k<i;k++)
f[i][j]=min(f[i][j],f[k][j-1]+a[k+1][i]);
printf("%d",f[n][t]);
}
显然a数组符合区间单调性,因此可以用四边形不等式优化。(见:http://blog.csdn.net/weixin_39872717/article/details/78765532)
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int s[501][501];
int f[501][501];
int a[501][501];
bool c[501];
int n,t;
int main()
{
scanf("%d%d",&n,&t);
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
for (int i=1;i<n;i++)
{
int l=0;
int r=0;
if (c[i]==1) l++; else r++;
for (int j=i+1;j<=n;j++)
{
if (c[j]==1)
l++;
else r++;
a[i][j]=l*r;
}
}
for (int i=1;i<=n;i++)
{
f[i][1]=a[1][i];
s[i][1]=1;
}
for (int j=2;j<=t;j++)
{
s[n+1][j]=n;
for (int i=n;i>=j;i--)
{
f[i][j]=2147483647;
for (int k=s[i][j-1];k<=s[i+1][j];k++)
if (f[k-1][j-1]+a[k][i]<f[i][j])
{
f[i][j]=f[k-1][j-1]+a[k][i];
s[i][j]=k;
}
}
}
printf("%d",f[n][t]);
}