您的位置:首页 > 大数据 > 人工智能

sgu183:Painting the balls(dp+优化)

2014-12-28 13:29 387 查看
题意:

在n(n<=10000)个球中,给若干个球涂色,每个球涂色的代价为Ci,使得任意连续m(m<=100)个球中有至少两个球被涂了色且总代价最小。

分析:

这个dp有点难想...

由于每次涂色的时候只与前两个涂色的球有关,因此设f[i][j]为倒数第二个涂色的为第i个球,最后一个涂色的球为第j个球的最小代价。

f[i][j]=min{f[k][i]}+c[j],由于区间[j-m,j-1]需要被覆盖,所以j-m<=k<i<j。

sgu内存限制只能滚动数组...

时间复杂度为O(n*m*m),话说应该过不了的,但竟然218ms过了...
/*
f[i][j]=min{f[k][i]}+c[j],j-m<=k<i<j;
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 10009, MAXM = 109, INF = 1e9;
int n, m;
int c[MAXN];
int f[MAXM][MAXM];
int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
	{
		cin >> c[i];
		f[0][i] = c[i];
	}
	for(int i = 1; i < n; ++i)
		for(int j = i+1; j < i+m && j <= n; ++j)
		{
			int minimum = INF;
			for(int k = max(0, j-m); k < i; ++k)
				minimum = min(minimum, f[k%MAXM][i%MAXM]);
			f[i%MAXM][j%MAXM] = minimum+c[j];
		}
	int ans = INF;
	for(int i = n-m+1; i < n; ++i)
		for(int j = i+1; j <= n; ++j)
			ans = min(ans, f[i%MAXM][j%MAXM]);
	cout << ans << endl;
	return 0;	
}


其实还可以优化:

f[i][j]=min{f[k][i]}+c[j],j-m<=k<i<j

f[i][j+1]=min{f[k][i]}+c[j+1],j-m+1<=k<i<j

我们可以发现f[i][j]与f[i][j+1]的搜索重叠部分为min{f[k][i]},j-m+1<=k<i<j

设g[i][j]=min{f[k][j]},那么g[i][j]=min{g[i][j+1],f[j-m][i]}。

时间复杂度O(n*m),31ms...
/*
f[i][j]=min{f[k][i]}+c[j],j-m<=k<i<j;
g[i][j]=min{f[k][i]},j-m<=k<i<j
g[i][j+1]=min{f[k][i]},j-m+1<=k<i<j
g[i][j]=min{g[i][j+1],f[j-m][i]};
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 10009, MAXM = 109, INF = 1e9;
int n, m;
int c[MAXN];
int f[MAXM][MAXM];
int mod[MAXN+MAXM];
int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		cin >> c[i];
	
	for(int i = 1; i <= n+m; ++i)
		mod[i] = i%MAXM; 
	
	for(int i = 1; i < m; ++i)
		for(int j = i+1; j <= m; ++j)
			f[i][j] = c[i]+c[j];
	
	for(int i = 1; i < n; ++i)
	{
		int tmp = INF;
		for(int j = i+m-1; j > i; --j)
		{
			if(j <= m) break;	
			tmp = min(tmp, f[mod[j-m]][mod[i]]);
			f[mod[i]][mod[j]] = tmp+c[j];
		}
	}
	
	int ans = INF;
	for(int i = n-m+1; i < n; ++i)
		for(int j = i+1; j <= n; ++j)
			ans = min(ans, f[mod[i]][mod[j]]);
	cout << ans << endl;
	return 0;	
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: