POJ 2923 状态压缩

这题不难,但过得人不多啊,POJ才不到600人过。。。。做的时候也比较顺利,仅仅PE了一次。

题意,有两辆车,容量分别为V1,V2,每次要运一定的物品到新家,经过几次后,把所有物品都运到新家,问最少用多少次。

N<=10,ok,铁定的状态压缩。

看起来不难,但想起来总感觉有点乱。想了半天才知道咋做。

首先预处理,分别搞出两辆车一次性可装的物品的状态。

接下来用f[i][x]表示第一辆车经过第i次的装运(可以小于i),能不能收集状态为x的物品组合。另一辆车类似的表示为g[i][x]

如果有满足f[i][x]和g[i][~x]均为真时,就找到了最小的i,也就是找到了答案。

另外,物品最好用a[0]来作为起点,这样初始化时比较方便。

附代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>

#define N 11
#define M 1100
#define u (1<<n)
#define cl(a) memset(a,0,sizeof(a)) 
#define ss(a) scanf("%d",&a)
#define pb push_back

using namespace std;

int f[N][M],g[N][M],a[N];
int v1,v2,n;
vector<int>f1,g1;
             
void inital(int i,int w,int v)
{
    if (i==n)
    {
        if (v<=v1) f1.pb(w);
        if (v<=v2) g1.pb(w);
        return;
    }
    inital(i+1,w,v);
    inital(i+1,w+(1<<i),v+a[i]);
} 

int check(int k)
{
    int i;
    for (i=0;i<u;i++)
        if (f[k][i]&&g[k][u-1-i]) return 1;
    return 0;
}

void start()
{
    cl(f);cl(g);
    f1.clear();g1.clear();
}

int main()
{
    int T,i,j,k,cas;
    ss(T);
    for (cas=1;cas<=T;cas++)
    {
        ss(n);
        ss(v1);ss(v2);
        for (i=0;i<n;i++) ss(a[i]);
        start();
        printf("Scenario #%d: \n",cas);
        inital(0,0,0);
        for (i=0;i<f1.size();i++) f[1][f1[i]]=1;
        for (i=0;i<g1.size();i++) g[1][g1[i]]=1;
        if (!check(1))
        {
            i=2;
            while (i<=n)
            {
                for (k=0;k<f1.size();k++)
                {
                    int t=f1[k];
                    for (j=t;j<u;j++)
                    {
                        if ((j&t)==t&&f[i-1][j-t]) f[i][j]=1;
                    }
                }
                for (k=0;k<g1.size();k++)
                {
                    int t=g1[k];
                    for (j=t;j<u;j++)
                    {
                        if ((j&t)==t&&g[i-1][j-t]) g[i][j]=1;
                    }
                }
                if (check(i)) 
                {
                    cout<<i<<endl;
                    break;
                }    
                i++;
            }
        }
        else cout<<1<<endl;
        cout<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值