模拟4

反思:133

1.T1分析问题死板,没有解决好状态转移的关系,背包模型不熟练

2.T2板子不熟练,tarjan

3.T3情况考虑不全面,暴力算法很水

 

T1

闲的没事又洛谷上AK了一道背包题
多重背包:优化版本
有一种物品有时候不选
那我就开一个正着f[i][j]//物品#钱数
一个反着
询问的时候再来一遍dp就行
思路很好,get it

失忆的 Eden 总想努力地回忆起过去,然而总是只能清晰地记得那种思念的感觉,却不能回忆起她的音容笑貌。 记忆中,她总是喜欢给 Eden 出谜题:在 valentine
's day 的夜晚,两人在闹市中闲逛时,望着礼品店里精巧玲珑的各式玩偶,她突发奇想,问了 Eden 这样的一个问题:有 nn 个玩偶,每个玩偶有对应的价值、价钱,每个玩偶都可以被买有限次,在携带的价钱 mm 固定的情况下,如何选择买哪些玩偶以及每个玩偶买多少个,才能使得选择的玩偶总价钱不超过 mm,且价值和最大。 众所周知的,这是一个很经典的多重背包问题,Eden 很快解决了,不过她似乎因为自己的问题被飞快解决感到了一丝不高兴,于是她希望把问题加难:多次询问,每次询问都将给出新的总价钱,并且会去掉某个玩偶(即这个玩偶不能被选择),再问此时的多重背包的答案(即前一段所叙述的问题)。 这下 Eden 犯难了,不过 Eden 不希望自己被难住,你能帮帮他么? 输入格式 第一行有一个整数,代表玩偶的个数 nn,玩偶从 00 开始编号。 第二行开始后面的 nn 行,每行三个整数,第 (i + 2)(i+2) 行的整数 a_i, b_i, c_ia i ​ ,b i ​ ,c i ​ ,分别表示买一个第 ii 个玩偶需要的价钱,获得的价值以及第 ii 个玩偶的限购次数。 接下来的一行有一个整数 qq,表示询问次数。 接下来 qq 行,每行两个整数 d_i, e_id i ​ ,e i ​ ,表示每个询问去掉的是哪个玩偶(注意玩偶从 00 开始编号)以及该询问对应的新的总价钱数。(去掉操作不保留,即不同询问互相独立)。 输出格式 输出 qq 行,第 ii 行输出对于第 ii 个询问的答案。 int f[1000+10][1200],n; int p[1000+10][1200]; int a[1000+10],b[1000+10],c[1000+10]; int q; inline void bag() { int ei=1000; _f(i,1,n) { int oi=c[i]; _f(j,0,1000) f[i][j]=f[i-1][j]; for(int k=1;k<=c[i];k<<=1) { for(int j=1000;j>=a[i]*k;j--)//整体意识! { f[i][j]=max(f[i][j],f[i][j-a[i]*k]+b[i]*k); // chu("f[%d]:%d\n",j,f[j]); } c[i]-=k; } if(c[i]) { int now=c[i]*a[i]; for(int j=1000;j>=now;j--) { f[i][j]=max(f[i][j],f[i][j-now]+b[i]*c[i]); // chu("f[%d]:%d\n",j,f[j]); } } c[i]=oi; } f_(i,n,1) { int oi=c[i]; _f(j,0,1000) p[i][j]=p[i+1][j]; for(int k=1;k<=c[i];k<<=1) { for(int j=1000;j>=a[i]*k;j--)//整体意识! { p[i][j]=max(p[i][j],p[i][j-a[i]*k]+b[i]*k); // chu("f[%d]:%d\n",j,f[j]); } c[i]-=k; } if(c[i]) { int now=c[i]*a[i]; for(int j=1000;j>=now;j--) { p[i][j]=max(p[i][j],p[i][j-now]+b[i]*c[i]); // chu("f[%d]:%d\n",j,f[j]); } } c[i]=oi; } return; } int main() { // freopen("gcdpro.in","r",stdin); // freopen("gcdpro.out","w",stdout); n=re(); _f(i,1,n) a[i]=re(),b[i]=re(),c[i]=re(); q=re(); bag(); _f(i,1,q) { int di=re(),ei=re(); di++; int ans=0; _f(j,0,ei) { ans=max(ans,f[di-1][j]+p[di+1][ei-j]); } chu("%d\n",ans); } return 0; }

 

你要购买m种物品各一件,一共有n家商店,你到第i家商店的路费为d[i],在第i家商店购买第j种物品的费用为c[i][j], 求最小总费用。

const int N=(1<<16)+100;
int f[110][N];
int c[110][20];
int n,m;

int main()
{
    freopen("prices.in","r",stdin);
    freopen("prices.out","w",stdout);
    n=re(),m=re();
    _f(i,1,n)
    {
        _f(j,0,m)
        c[i][j]=re();
    }
    int maxn=(1<<(m));
    int ans=inf;
    memset(f,0x7f,sizeof(f));
    f[0][0]=0;
    _f(i,1,n) 
    {
        _f(j,0,maxn-1)
        {
            f[i][j]=f[i-1][j]+c[i][0];
        }
        _f(j,0,maxn-1)
        {
            _f(k,0,m-1)
            {
                if((j&(1<<(k)))==0)
                {
                    f[i][j|(1<<k)]=min(f[i][j|(1<<k)],f[i][j]+c[i][k+1]);//把这个买上 
                }
            }
        }
        _f(j,0,maxn-1)
        {
            f[i][j]=min(f[i-1][j],f[i][j]);
        }
        ans=min(ans,f[i][maxn-1]);
    }
    chu("%d",ans);
    return 0;
 }
 /*
f[i][j]:表示到了第i个商店,达到状态j的最小花费 
 for()//枚举买到了哪个超市
     for()//枚举我从哪个状态出发
         for()//枚举在这个超市买什么,因为我默认在这个超市买东西,所以在第一次循环加上费用,以后就不用再加了,
         也就默认(保证)了我在这个超市可以买多个商品而不用多付钱
         所以我的问题也就解决了(重复算一个超市的跑路钱) 

 

posted on 2022-05-25 17:34  HZOI-曹蓉  阅读(67)  评论(0)    收藏  举报