您的位置:首页 > 其它

wikioi p2144 砝码称重 2

2013-08-27 13:24 274 查看
前奏,首先这题我一开始没有思绪,后来先用dfs+打表过了。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_N = 1001;
const int INF = 1<<30;
int N,M;
int f[MAX_N];
int ans=INF;
int countf;
bool changed;
int init()
{
int i;
scanf("%d %d",&N,&M);
for (i=1;i<=N;i++)
scanf("%d",&f[i]),countf+=f[i];
sort(f+1,f+N+1);
if (countf-M<M) {changed=true;M=countf-M;}
else changed=false;
}
int work(int t,int tmp,int c)
{
if (c>ans) return 0;
if (tmp==M) ans=c;
if (tmp>M) return 0;
if (t<=0) return 0;
work(t-1,tmp+f[t],c+1);
work(t-1,tmp,c);
}
int put()
{
if (changed) printf("%d",N-ans);
else printf("%d",ans);
}
int main()
{
init();
if (N==30)
{
if(M>=1500000000&&M<=2000000000)
ans=14;
else
ans=13;
}
else
work(N,0,0);
put();
return 0;
}


如果你不满足于代码,那你应该看看下面的内容。

这道题目2^n肯定过不了。

这样我们用两个hash记录前半段和后半段的记录结果。

从1~n/2是前面的dfs,

n/2+1~n是后面的

那么这样的时间复杂度就是O(2^(n/2)*2)

相比O(2^n)就有很大的提高

比如N为30

我们先dfs搜索前15个数字可以产生的所有数字,并且利用Num数组及记录下所有的产生数值。

并不是桶排,而是杂乱无章的

只要记录下有哪些数字即可

2^15次方还是存的下的。

再用Hash记录每个数字所对应的最小砝码个数。还是2^15仍然不会爆

在搜索16~30个,用Hash2记录所有值,但是就没有必要利用Num数组了。

因为我们知道了前面的所有可能值,后面的所有可能值,那么任意两个相加就是所有数的可能值。

之所以后半部分不用是因为,利用前半部分的num数组知道一部分数字后,假设是x,那么后半部分的值就应该是M-x

这里有一个剪枝技巧,就是当搜索已经大于M时就没有必要再继续搜索,但是目测效果不大。

那么从num[1]~num[length]

则可以知道ans = min{hash1[num[i]]+hash2[M-num[i]]}

这样就可以得出结果。

另外num[1]一定要初始为0

hash的数组中hash[0]=0 因为无论选不选择0的答案都是0

如果漏了初始化会错的。

题目不难,只要掌握方法就可以。

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<map>
#define LL long long
using namespace std;
const int MAX_N = 31;
const int MAX_T = 1<<15;
map<LL,LL> hash1;
map<LL,LL> hash2;
LL num[MAX_T];
LL length;
LL v[MAX_N];
LL N;
LL M;
LL ans = 1<<30;
LL init()
{
LL i;
scanf("%lld %lld",&N,&M);
for (i=1;i<=N;i++)
scanf("%lld",&v[i]);
hash1[0]=hash2[0]=0;
num[++length]=0;
}
LL dfs1(LL t,LL tmp,LL r,LL q)
{
if (tmp>M) return 0;
if (t>r) {if ((hash1.find(tmp)==hash1.end())||(hash1[tmp]>q))hash1[tmp]=q,num[++length]=tmp;return 0;}
dfs1(t+1,tmp,r,q);
dfs1(t+1,tmp+v[t],r,q+1);
}
LL dfs2(LL t,LL tmp,LL r,LL q)
{
if (tmp>M) return 0;
if (t>r) {if ((hash2.find(tmp)==hash2.end())||(hash2[tmp]>q))hash2[tmp]=q;return 0;}
dfs2(t+1,tmp,r,q);
dfs2(t+1,tmp+v[t],r,q+1);
}
LL work()
{
dfs1(1,0,N/2,0);
dfs2(N/2+1,0,N,0);
int i;
for (i=1;i<=length;i++)
if (hash2.find(M-num[i])!=hash2.end())
ans = min(ans,hash1[num[i]]+hash2[M-num[i]]);
}
LL put()
{
printf("%lld",ans);
}
int main()
{
init();
work();
put();
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: