关灯问题

  
想去写dp 所以就写了dp 这道dp 写的有点失败了,因为我根本 无法实现状态转移,最后看了眼学长的博客。

求 n个灯分成m组 的最大照明度 毫无疑问的是 设 f[i][j] 表示前i 个灯分成j组能 得到的最大照明。

可是状态转移的时候 无法转移 纵使我想到了前缀和 但是 唯一缺漏之处是 发现一组的灯里还有不能用的。

这就很气了,我不知道当前枚举的灯哪个用哪个不用 ,好像写不下去了。

一组灯中 有不用的灯这不是让搜索么?况且 我还是在一个三重循环中搜索这肯定不行 。

学长是这样写的 先预处理出 g[i][j] 表示第i个灯到第j个灯的最大照明度。

对于这一个区间采用搜索寻找出最大的照明度 ,我是真的没想到这是一个01背包问题。

有容积有价值 为什么不01背包,还是太年轻。又是没想到。。。

朴素的处理是这样的

for(int i=1;i<=n;++i)
        for(int j=i;j<=n;++j)
        {
            int s=T*(j-i+1);
            memset(w,0,sizeof(w));
            for(int k=i;k<=j;++k)
                for(int r=s;r>=a[k];r--)
                    w[r]=max(w[r],w[r-a[k]]+z[k]);
            g[i][j]=w[s];
        }
View Code

可是这是接近n^4的复杂度一定GG。

考虑 怎么搞 我不太会。。

其实可以这样 对于枚举出的每个i j 灯的个数和体积在增长。

那么 直接拿出 i~n的全部容量再对每个新出现的灯进行01背包即可 最后只取i~j的容量的价值即可复杂度接近n^3 能A 了。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 2147483646
#define ll long long
#define R register
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
inline void put(int x)
{
    x<0?putchar('-'),x=-x:0;
    int num=0;char ch[50];
    while(x)ch[++num]=x%10+'0',x/=10;
    num==0?putchar('0'):0;
    while(num)putchar(ch[num--]);
    putchar('\n');return;
}
const int MAXN=200;
int n,m,T,maxx;
int a[MAXN],z[MAXN];
int f[MAXN][MAXN];//f[i][j]表示前i个电灯分成j组能得到的最大照明
int g[MAXN][MAXN];//g[i][j]表示第i个电灯到第j个电灯为一组的最大照明
int w[MAXN*50];
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();T=read();
    for(int i=1;i<=n;++i)a[i]=read(),z[i]=read();
    for(int i=1;i<=n;++i)
    {    
        int s=T*(n-i+1);
        memset(w,0,sizeof(w));
        for(int j=i;j<=n;++j)
        {
            for(int r=s;r>=a[j];r--)
                w[r]=max(w[r],w[r-a[j]]+z[j]);
            g[i][j]=w[T*(j-i+1)];
        }
    }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            for(int k=j-1;k<i;++k)
                f[i][j]=max(f[i][j],f[k][j-1]+g[k+1][i]);
    put(f[n][m]);
    return 0;
}
View Code
posted @ 2019-03-27 21:36  chdy  阅读(213)  评论(0编辑  收藏  举报