2021年第十二届蓝桥杯省赛B组C/C++赛道

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;
} 

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值