HDU 4381 Grid

背包变形。

将操作分为了两类,可以分开处理。

可以dp处理出L[i]:L[i]=-1代表从左到右 i 长度不能被拼凑出来,L[i]!=-1表示从左到右 i 长度能被拼凑出,并且最小费用为L[i]。

反着来一次dp就可以处理出R[i]:R[i]=-1代表从右到左 n+1-i 长度不能被拼凑出来,R[i]!=-1表示从右到左 n+1-i 长度能被拼凑出,并且最小费用为R[i]。

由L[1---i] 与R[i+1---n]可以得出,以i为分割的最优解,于是,枚举 i 即可。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}
inline int read()
{
    char c = getchar();  while(!isdigit(c)) c = getchar();
    int x = 0;
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
    return x;
}

const int maxn=1000+10;
int T,n,m;
struct X { int op,a,x; }s[maxn];
bool cmp1(X a,const X b) { return a.a<b.a; }
bool cmp2(X a,const X b) { return a.a>b.a; }
int L[maxn],R[maxn];

int main()
{
    scanf("%d",&T); int cas=1; while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d%d%d",&s[i].op,&s[i].a,&s[i].x);
        sort(s+1,s+1+m,cmp1);

        memset(L,-1,sizeof L); L[0]=0;
        for(int i=1;i<=m;i++)
        {
            if(s[i].op!=1) continue;
            for(int j=n;j>=0;j--)
            {
                if(L[j]==-1) continue; if(j+s[i].x>s[i].a) continue;
                if(L[j+s[i].x]==-1) L[j+s[i].x]=L[j]+1;
                else L[j+s[i].x]=min(L[j+s[i].x],L[j]+1);
            }
        }

        memset(R,-1,sizeof R); R[n+1]=0;
        sort(s+1,s+1+m,cmp2);
        for(int i=1;i<=m;i++)
        {
            if(s[i].op!=2) continue;
            for(int j=1;j<=n+1;j++)
            {
                if(R[j]==-1) continue; if(j-s[i].x<s[i].a) continue;
                if(R[j-s[i].x]==-1) R[j-s[i].x]=R[j]+1;
                else R[j-s[i].x]=min(R[j-s[i].x],R[j]+1);
            }
        }
        int ans1=0,ans2=0;
        for(int i=0;i<=n;i++)
        {
            int a1=0,a2=0,b1=0,b2=0;
            for(int j=i;j>=0;j--) { if(L[j]==-1) continue; a1=j,a2=L[j]; break; }
            for(int j=i+1;j<=n+1;j++) { if(R[j]==-1) continue; b1=n+1-j,b2=R[j]; break; }
            if(a1+b1>ans1) ans1=a1+b1, ans2=a2+b2;
            else if(a1+b1==ans1) ans2=min(ans2,a2+b2);
        }
        printf("Case %d: %d %d\n",cas++,ans1,ans2);
    }
    return 0;
}

 

posted @ 2016-08-07 21:21  Fighting_Heart  阅读(150)  评论(0编辑  收藏  举报