划分大理石(多重背包)
前言
发现自己思路好像和正常人不一样
遂有此篇博客
划分大理石
问题描述
有价值分别为 \(1..6\) 的大理石各 \(a[1..6]\) 块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现。
其中大理石的总数不超过 \(20000\) 。
输入格式:
输入包含多组数据!
每组数据占一行,包含 \(6\) 个整数,表示 \(a[1]∼a[6]\) 。
当输入为 \(0 0 0 0 0 0\) 时表示输入结束,且该行无需考虑。
输出格式:
每组数据输出一个结果,每个结果占一行。
如果可以实现则输出 \(Can\),否则输出 \(Can't\)。
样例输入:
4 7 4 5 9 1
9 8 1 7 2 4
6 6 8 5 9 2
1 6 6 1 0 7
5 9 3 8 8 4
0 0 0 0 0 0
样例输出:
Can't
Can
Can't
Can't
Can
分析
很显然啊,多重背包,而且不问你方案,这就很nice
板子是这样的
bool f[10005];
memset(f,0,sizeof);
f[0]=1;
for (int i=1;i<=6;++i)
for (int j=1;j<=a[i];++j)
for (int k=m;k>=a[i];--k)
f[k]|=f[k-a[i]];
if (f[sum/2]) ...;
else ...;
显然会 TLE Time Limit Enough
考虑优化
考虑到若前\(i\)种石头能凑出\(sum/2\),只有两种情况:
- 在\(i\)之前, 就已经\(f[j]=true\)
- 在\(i\)之前, 就已经\(f[j-i]=true\)
于是考虑贪心
设 \(vis[j]\) 表示 \(f[j]\) 在阶段 \(i\) 是为 \(true\) 的情况下至少需要多少块 \(i\) 种石头
则板子的 \(for(j) for(k)\) 循环可以优化1维,直接正序扫面
当 \(!f[j] \&\& f[j-i] \&\& vis[j-i] ﹤ a[i]\) 才可以转移
于是开心的提交
TLE
为啥呢 被hack了
考虑剪枝
发现如果每个价值的大理石都是 \(2\) 的倍数,那么必能分成两部分价值相等 (感谢oistars提供的想法)
于是AC了
code
Elaina's code
#include<bits/stdc++.h>
using namespace std;
const int N=150000;
#define rd read()
#define int long long
#define inf 0x3f
#define INF 0x3f3f3f3f
#define mst(a,b) memset(a,b,sizeof(a))
#define re register
#define Elaina 0
inline int read(){
int x=0,f=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
int n,m,a[8],sum,hsum,f[N],vis[N];
main(){
#ifdef ONLINE_JUDGE
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
#endif
while(1){
sum=0;
for(int i=1;i<=6;++i){
a[i]=rd;
}
if(!a[1]&&!a[2]&&!a[3]&&!a[4]&&!a[5]&&!a[6]) break;
sum=a[1]%2+a[2]%2+a[3]%2+a[4]%2+a[5]%2+a[6]%2;
if(!sum){
printf("Can\n");
continue;
}
sum=a[1]+a[2]*2+a[3]*3+a[4]*4+a[5]*5+a[6]*6;
if(sum%2){
printf("Can't\n");
continue;
}
mst(f,0);
f[0]=1;
hsum=sum/2;
for(int i=1;i<=6;++i){
mst(vis,0);
for(int j=0;j<=hsum;++j){
if(f[j]&&!f[j+i]&&vis[j]<a[i]){
f[j+i]=1;
vis[j+i]=vis[j]+1;
}
}
}
if(f[hsum]) printf("Can\n");
else printf("Can't\n");
}
return Elaina;
}
别急,还有后续
又双叒叕被卡了
都看到这了,真的不点个赞吗(>ω<*)