sgu183:Painting the balls(dp+优化)

来源:互联网 发布:程序员 欣欣 编辑:程序博客网 时间:2024/05/29 19:27
题意:
在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<jg[i][j+1]=min{f[k][i]},j-m+1<=k<i<jg[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;}

1 0