G题砝码称重
给出两种解法
解法一(转载大佬代码)
思路:dp
初始设dp[102][100002]
dp[i][j]为1代表前i个砝码可以称出质量j,为0代表不能称出来;
两层循环里一定有:
dp[i][j]=dp[i-1][j] //因为前i-1可以称出来的质量前i个照样能!
如果dp[i][j]仍未0,那么看j和w[i]的关系:
j==w[i],则dp[i][j]=1;
否则dp[i][j]=dp[i-1][abs(j-w[i])];
最后数一下有多少个为1的即可。
dp代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[102][100002];
int main()
{
int n;
scanf("%d",&n);
int w[n+1];
ll sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
sum+=w[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=sum;j++){
dp[i][j]=dp[i-1][j];
if(dp[i][j]==0){
if(w[i]>j)dp[i][j]=dp[i-1][w[i]-j];
if(w[i]==j)dp[i][j]=1;
if(w[i]<j)dp[i][j]=dp[i-1][j-w[i]];
}
}
}
ll ans=0;
for(int i=1;i<=sum;i++){
if(dp[n][i])ans++;
}
printf("%lld",ans);
return 0;
}
解法二(C实现)
思路: 树
将每一个读入的砝码重量作为一层,其中树的根节点为0节点,除根节点外的每一棵子树的根节点存index、0(解决不相邻砝码称重问题)、-index,
每次值存到相应根节点时,将此时的下标入栈PUSH保存起来,递归到叶子节点时,返回时将前一次的下标POP出栈,找到对应值(-index)传入右子树;
树的每个节点保存的是从根节点到当前节点可以称出的砝码重量,存入相应节点时,如果重量非负,存到HashTable。
最后遍历哈希表,找出所有索引下标非空的值,计数输出。
贴代码
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
struct tree{
int sum;
struct tree *father;
struct tree *lchild;
struct tree *zerochild;
struct tree *rchild;
};
struct hash{
int val;
struct hash *next;
};
struct hash HashTable[10005];
int arr[10005];
int resul[10005];
int stack[10005]; //m入栈 保存现场
int count = 0;
int k = 0;
int m = -1;
int s=0;
int hash(int index)
{
return index%10003;
}
void PUSH_Hashtable(int value)
{
struct hash *tmp = NULL;
struct hash *p = NULL;
struct hash *q = NULL;
tmp = HashTable[hash(value)].next;
p = (struct hash *)malloc(sizeof(struct hash));
p->val = value;
p->next = NULL;
while(tmp!=NULL){
q = tmp;
tmp = tmp->next;
}
if(q!=NULL)
{
p->next = q->next;
q->next = p;
}
else{
HashTable[hash(value)].next = p;
}
}
void build_tree(struct tree *t,int n,int val,int flag)
{
//int index=-1;
//t = (struct tree *)malloc(sizeof(struct tree));
struct tree *lc = NULL;
struct tree *zc = NULL;
struct tree *rc = NULL;
stack[s++] = m; //m压栈 递归改变m 先保存
m++;
if( m<n ){
lc = (struct tree *)malloc(sizeof(struct tree));
zc = (struct tree *)malloc(sizeof(struct tree));
rc = (struct tree *)malloc(sizeof(struct tree));
lc->father = t;
zc->father = t;
rc->father = t;
}
t->lchild = lc;
t->zerochild = zc;
t->rchild = rc;
if( flag==0 ){ //根节点
t->sum = 0;
t->father = NULL;
}
else{
t->sum = (t->father)->sum + val;
//resul[k++] = t->sum;
if( t->sum>0 ){
PUSH_Hashtable(t->sum);
}
}
if( m==n )
{
//s -= 1;
m = stack[--s]; //弹栈
return ;
}
else{
build_tree(t->lchild,n,arr[m],1);
build_tree(t->zerochild,n,0,1); // 0节点 为了覆盖全部情况
build_tree(t->rchild,n,-arr[m],1);
}
m = stack[--s]; //弹栈 恢复m
return;
}
int main()
{
int i=0,j=0;
int n;
int tmp;
struct tree *p=NULL;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&arr[i]);
resul[k++] = arr[i];
}
p = (struct tree *)malloc(sizeof(struct tree));
build_tree(p,n,0,0);
printf("weight is:[");
for(i=0;i<10005;i++)// printf("%d ",resul[i]);
{
if(HashTable[i].next!=NULL){
printf("%d ",(HashTable[i].next)->val);
count++;
}
else
continue;
}
printf("]\n");
printf("num is %d",count);
/*
for(i=0;i<k;i++)
{
for(j=i+1;j<k;j++)
{
if(resul[i]>resul[j]){
tmp = resul[i];
resul[i]=resul[j];
resul[j]=tmp;
}
}
}
for(i=0;i<k;i++) printf("%d ",resul[i]);
*/
//删除重复重量
return 0;
}