模拟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()//枚举在这个超市买什么,因为我默认在这个超市买东西,所以在第一次循环加上费用,以后就不用再加了, 也就默认(保证)了我在这个超市可以买多个商品而不用多付钱 所以我的问题也就解决了(重复算一个超市的跑路钱)
浙公网安备 33010602011771号