poj 2430 Lazy Cows 状压dp

本文探讨了使用状态DP(动态规划)解决特定问题的方法,特别是如何处理状态转移和离散化带来的挑战。通过实例分析,展示了如何通过优化状态定义和转移过程来求解最优解。

这个题目还是比较容易想到用状态dp来解的,但是状态的转移比较麻烦,并且加上有离散化,比较容易出错。

dp[i][j][k]表示覆盖前i列,用了j个矩形,当前覆盖状态为k的最优解。

k==1:覆盖1号格子

k==2:覆盖2号格子

k==3:覆盖1,2号格子,并且为同一个矩形

k==4:覆盖1,2号格子,并且为不同矩形

那么转移的时候就需要考虑,新建矩形,或者直接把当前矩形边长延伸。转移种类较多。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e3+9;
bool a[3][maxn];
int x[maxn],y[maxn],f[maxn],g[maxn];
int dp[maxn][maxn][5];
struct D
{
    int id,key;
    bool operator <(const D & xx) const
    {
        return key<xx.key;
    }
}h[maxn];
int main()
{
//    freopen("in.txt","r",stdin);
    int n,K,b;
    while(scanf("%d %d %d",&n,&K,&b)!=EOF)
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
            scanf("%d %d",&x[i],&y[i]);
            h[i].key=y[i],h[i].id=i;
        }
        sort(h+1,h+1+n);
        int top=0;
        f[h[1].id]=++top;
        g[top]=h[1].key;
        for(int i=2;i<=n;i++)
        {
            if(h[i].key!=h[i-1].key) ++top;
            f[h[i].id]=top;
            g[top]=h[i].key;
        }
        for(int i=1;i<=n;i++)
        a[x[i]][f[i]]=1;

        memset(dp,50,sizeof(dp));
        dp[0][0][0]=0;
        for(int k=0;k<top;k++)
        {
            for(int i=0;i<=K;i++)
            for(int j=0;j<5;j++)
            {
                if(a[1][k+1]==0)
                dp[k+1][i+1][2]=min(dp[k+1][i+1][2],dp[k][i][j]+1);

                if(a[2][k+1]==0)
                dp[k+1][i+1][1]=min(dp[k+1][i+1][1],dp[k][i][j]+1);

                dp[k+1][i+1][3]=min(dp[k+1][i+1][3],dp[k][i][j]+2);
                dp[k+1][i+2][4]=min(dp[k+1][i+2][4],dp[k][i][j]+2);

                if(j==1)
                {
                    if(a[2][k+1]==0)
                    dp[k+1][i][j]=min(dp[k+1][i][j],dp[k][i][j]+g[k+1]-g[k]);
                    else
                    dp[k+1][i+1][4]=min(dp[k+1][i+1][4],dp[k][i][j]+g[k+1]-g[k]+1);
                }
                else if(j==2)
                {
                    if(a[1][k+1]==0)
                    dp[k+1][i][j]=min(dp[k+1][i][j],dp[k][i][j]+g[k+1]-g[k]);
                    else
                    dp[k+1][i+1][4]=min(dp[k+1][i+1][4],dp[k][i][j]+g[k+1]-g[k]+1);
                }
                else if(j==3)
                {
                    dp[k+1][i][j]=min(dp[k+1][i][j],dp[k][i][j]+(g[k+1]-g[k])*2);
                }
                else if(j==4)
                {
                    dp[k+1][i][j]=min(dp[k+1][i][j],dp[k][i][j]+(g[k+1]-g[k])*2);

                    if(a[2][k+1]==0)
                    dp[k+1][i][1]=min(dp[k+1][i][1],dp[k][i][j]+g[k+1]-g[k]);
                    else
                    dp[k+1][i+1][4]=min(dp[k+1][i+1][4],dp[k][i][j]+g[k+1]-g[k]+1);

                    if(a[1][k+1]==0)
                    dp[k+1][i][2]=min(dp[k+1][i][2],dp[k][i][j]+g[k+1]-g[k]);
                    else
                    dp[k+1][i+1][4]=min(dp[k+1][i+1][4],dp[k][i][j]+g[k+1]-g[k]+1);
                }
            }
        }

        int ans=1e9;

        for(int k=0;k<=K;k++)
        for(int i=0;i<5;i++)
        ans=min(ans,dp[top][k][i]+K-k);
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值