(一题多解)Holding Bin-Laden Captive!(母函数模板变形、DP、多重背包)

Link:http://acm.hdu.edu.cn/showproblem.php?pid=1085

Holding Bin-Laden Captive!

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 15763    Accepted Submission(s): 7064


Problem Description
We all know that Bin-Laden is a notorious terrorist, and he has disappeared for a long time. But recently, it is reported that he hides in Hang Zhou of China! 
“Oh, God! How terrible! ”



Don’t be so afraid, guys. Although he hides in a cave of Hang Zhou, he dares not to go out. Laden is so bored recent years that he fling himself into some math problems, and he said that if anyone can solve his problem, he will give himself up! 
Ha-ha! Obviously, Laden is too proud of his intelligence! But, what is his problem?
“Given some Chinese Coins (硬币) (three kinds-- 1, 2, 5), and their number is num_1, num_2 and num_5 respectively, please output the minimum value that you cannot pay with given coins.”
You, super ACMer, should solve the problem easily, and don’t forget to take $25000000 from Bush!
 

Input
Input contains multiple test cases. Each test case contains 3 positive integers num_1, num_2 and num_5 (0<=num_i<=1000). A test case containing 0 0 0 terminates the input and this test case is not to be processed.
 

Output
Output the minimum positive value that one cannot pay with given coins, one line for one case.
 

Sample Input
  
1 1 3 0 0 0
 

Sample Output
  
4
 

Author
lcy
 
My code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
	int c1[8888],c2[8888];
	int i,j,k,n[4];
	while(scanf("%d%d%d",&n[1],&n[2],&n[3])!=EOF)
	{
		if(n[1]==0&&n[2]==0&&n[3]==0)
			break;
		memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
		for(i=0;i<=n[1];i+=1)
		{
			c1[i]=1;
		}
		for(i=0;i<=n[1]*1;i+=1)
		{
			for(j=0;j<=n[2]*2;j+=2)
			{
				c2[j+i]+=c1[i];
			}
		}
		for(i=0;i<=n[1]*1+n[2]*2;i++)
		{
			c1[i]=c2[i];
			c2[i]=0;
		}
		for(i=0;i<=n[2]*2+n[1]*1;i++)
		{
			for(j=0;j<=n[3]*5;j+=5)
			{
				c2[j+i]+=c1[i];
			}
		}
		for(i=0;i<=n[1]*1+n[2]*2+n[3]*5;i++)
		{
			c1[i]=c2[i];
			c2[i]=0;
		}
		for(i=1;;i++)
		{
			if(!c1[i])
			{
				printf("%d\n",i);
				break;
			}
		}
	}
	return 0;
}


code2:

以下参考:http://acm.hut.edu.cn/?p=277

/题意:给你面值是125的硬币的数量,要你求由这些硬币不能组成的最小的金额。。

下面给出3种方法;
//
方法1:很明显母函数
//
我这里一步一步的求。。
//
下面是我的一点理解。。如果叫你写由面值1,2,5的硬币所组成的金额的母函数
//Y=(1+x+x^2+x^3+x^4…+x^n1*1)*(1+x^2+x^4+x^6…x^n2*2)*(1+x^5+x^10+…x^n3*5)


#include<stdio.h>

#include<string.h>

#define MAX 10010

int num[3];

int val[3]={1,2,5};

int n;

int c1[MAX],c2[MAX];

int main( )

{
	
	while(scanf("%d%d%d",&num[0],&num[1],&num[2]),num[0]||num[1]||num[2])
		
	{
		
		int i,j,k,t;
		
		n=num[0]*1+num[1]*2+num[2]*5;// num[0]*val[0]+num[1]*val[1]+num[2]*val[3] budui
		
		memset(c1,0,sizeof(c1));
		
		memset(c2,0,sizeof(c2));
		
		for( i=0;i<=num[0];i+=val[0])
			
		{
			
			c1[i]=1;
			
		}
		
		for( i=1;i<=2;i++)
			
		{
			
			
			
			for( j=0;j<=n;j++)
				
				for( k=0;k<=num[i]*val[i]&&k+j<=n;k+=val[i])
					
					c2[j+k]+=c1[j];
				
				for(t=0;t<=n;t++)
					
				{
					
					c1[t]=c2[t];
					
					c2[t]=0;
					
				}
				
		}
		
		for(i=0;i<=n+1;i++)
			
			if(c1[i]==0)
				
				
				
			{
				
				printf("%d\n",i);
				
				break;
				
				
				
			}
			
			
			
	}

	return 0;

	
}


上面代码的for循环可合并代码:

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int N=8010;

int num[4],money[4]={0,1,2,5};
int c1[N],c2[N];

int main(){

    //freopen("input.txt","r",stdin);

    while(~scanf("%d%d%d",&num[1],&num[2],&num[3])){
        if(num[1]==0 && num[2]==0 && num[3]==0)
            break;
        for(int i=0;i<N;i++){
            c1[i]=0;
            c2[i]=0;
        }
        c1[0]=1;
        int maxx=0;
        for(int i=1;i<=3;i++){
            maxx+=num[i]*money[i];
            for(int j=0;j<=maxx;j++)
                for(int k=0;k<=num[i] && j+k*money[i]<=maxx;k++)
                    c2[j+k*money[i]]+=c1[j];
            for(int j=0;j<=maxx;j++){
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        for(int i=1;;i++)
            if(c1[i]==0){
                printf("%d\n",i);
                break;
            }
    }
    return 0;
}


注:此代码可改为每种种类个数无限的情况,给出模板如下

针对此题:http://acm.hdu.edu.cn/showproblem.php?pid=1028

#include<stdio.h>
#include<string.h>
#define MAX 10010
int num[3];
int val[3]={1,2,5};
int n,m;
int c1[MAX],c2[MAX];
int main()
{
	while(scanf("%d",&m)!=EOF)
	{
		int i,j,k,t;
		memset(c1,0,sizeof(c1));
		memset(c2,0,sizeof(c2));
		for( i=0;i<=m;i++)	
		{
			c1[i]=1;
			c2[i]=0;
		}
		for( i=2;i<=m;i++)	
		{
			for(j=0;j<=m;j++)
				for( k=0;k+j<=m;k+=i)
					c2[j+k]+=c1[j];
				for(t=0;t<=m;t++)	
				{
					c1[t]=c2[t];
					c2[t]=0;	
				}		
		}
				printf("%d\n",c1[m]);		
	}
	return 0;	
}


HDU 1085 HoldingBin-Laden Captive!

分类: 三、动态规划之--硬币系统2012-10-0216:39 89人阅读 评论(0) 收藏 举报

  poj 1085 

  题目大意: 有一个币值系统,里面有 1元,2元,5元,其数量分别为 num1 张,num2 张,num3张, 

 现在需要求出最小不能表示的币值。

  解题思路:

    可以分为三类:1)没有 元的,那么输出 1

                 2)没有5 元的或者(1,2 元的价值总和小于 4),那么输出值为 num1+2 * num2+1

                 31,2 元的价值总和= 4,那么就可以 4—5,即最大可表示数为:num1+2 *num2+5*num3

 

code


#include<stdio.h>
int main()
{
   int num1,num2,num3,max12,max;
   while(1)
    {
       scanf("%d%d%d",&num1,&num2,&num3);
       if(num1==0&&num2==0&&num3==0)break;
       if(num1==0){printf("1\n");continue;}
        max12=num2*2+num1;
       if(num3==0||max12<4)
       {printf("%d\n",max12+1);continue;}
       //只要有一个4,就可以变为5;即最大数为下面的max
       max=num1+num2*2+num3*5;
       printf("%d\n",max+1);
    }
   return 0;
}
 


3.多重背包方法:

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

int num[3],money[3]={1,2,5};
int dp[8010];

int main(){

    //freopen("input.txt","r",stdin);

    while(~scanf("%d%d%d",&num[0],&num[1],&num[2])){
        if(num[0]==0 && num[1]==0 && num[2]==0)
            break;
        memset(dp,0,sizeof(dp));
        int tot=num[0]*1+num[1]*2+num[2]*5;
        dp[0]=1;
        for(int i=0;i<3;i++)    //简单的多重背包
            for(int j=0;j<num[i];j++)
                for(int k=tot;k>=money[i];k--)
                    dp[k]+=dp[k-money[i]];
        int ans=tot+1;
        for(int i=1;i<=tot;i++)
            if(dp[i]==0){
                ans=i;
                break;
            }
        printf("%d\n",ans);
    }
    return 0;
}


<think>我们正在分析一段STL(语句表)代码:`LDBW2`和 `AnlageDB numberload andcompare with0`。首先,需要明确STL是西门子STEP7(TIA Portal)中的一种低级编程语言,类似于汇编语言。1.**理指令**:- `L DBW2`:这条指令的意思是加载(Load)数据块(DB)中地址为2的一个字(Word)到累加器1(ACCU1)。这里DBW表示数据块中的字(Word),地址为2。注意:在西门子PLC中,数据块中的地址通常以字节为单位,而一个字占两个字节。因此,DBW2表示从数据块的第2个字节开始的一个字(即占用第2和第3字节)。-接下来,用户提到“AnlageDB numberload andcompare with0”。这里“Anlage”可能是德语,意为“设备”或“系统”,但在此上下文中,更可能是用户描述的一部分。实际上,我们只看到了`L DBW2`,并没有看到比较指令。通常,比较指令会是`==0`、`<>0`等。所以,用户可能想表达的是:加载数据块中的某个字(DBW2)并与0比较。2.**完整的比较代码**:如果用户想要比较DBW2的值是否为0,那么后续的指令可能是:-`LDBW2`//将DBW2的值加载到累加器1- `==0`//与0比较(如果等于0,则RLO(逻辑运算结果)为1,否则为0)或者使用其他比较指令,如`<>0`(不等于0)、`>0`(大于0)等。3.**示例**:假设我们有一个数据块DB1,我们想检查DB1.DBW2是否等于0,然后在等于0时执行某个操作(比如置位一个位),代码可能如下:```OPN DB1//打开数据块DB1LDBW2//加载DB1.DBW2到ACCU1==0//比较ACCU1是否等于0=Q0.0//如果等于0,则置位Q0.0(输出位)```4. **注意**:-在STL中,比较指令会检查累加器1的内容与指定值(或另一个累加器的内容)的关系,并将比较结果(布尔值)存储在状态字的RLO中。-在STL中,数据块必须先打开(使用OPN指令)才能访问。如果之前已经打开了数据块,则无需再次打开。5.**用户意图**:用户可能是在调试一段代码,其中加载了数据块中的某个值(DBW2)并与0比较。需要确认比较的结果用于后续逻辑控制。6.**可能的问题**:-如果用户没有看到预期的比较结果,需要检查:-数据块是否正确打开?-数据块中地址2处的字是否被正确写入?-比较指令是否正确?7.**相关引用**:关于STL编程,可以参考西门子的官方文档[^1]。另外,关于C++ STL的引用(用户提供的引用[1]和[2])与这里的STL(语句表)无关,请注意区分。8.**生成相关问题**:根据用户的问题,生成以下相关问题:§§相关问题§§1.在STL中,如何正确打开数据块并访问其中的数据?2.STL中比较指令有哪些?如何使用?3.如何监控STL程序中数据块的值?4.在TIA Portal中如何调试STL程序?5.STL中累加器的作用是什么?6.数据块中DBW2的地址范围是少?它占用哪些字节?</think>### STL代码分析:`L DBW 2` 和比较操作 在西门子TIA Portal的STL(语句表)语言中,您提供的代码涉及数据块加载和比较操作。以下是分步析: #### 1. **指令分** - **`L DBW 2`** - `L`:加载指令(Load),将数据复制到累加器1(ACCU1) - `DBW`:数据块字类型(Data Block Word),表示16位有符号整数 - `2`:数据块中的字节偏移地址 - **含义**:从当前打开的数据块(DB)中,读取偏移地址2处的16位字(占用地址2和3),将其加载到累加器1。 - *示例*:若`DB1.DBW2`值为`-5`,执行后ACCU1 = `-5`。 - **比较操作** 虽然没有给出完整比较指令,但典型用法是: ```stl L DBW 2 // 加载DBW2的值到ACCU1 ==0 // 比较ACCU1是否等于0 = Q0.0 // 若等于0,则置位输出Q0.0 ``` 关键比较指令: - `==0`:判断ACCU1是否等于0 - `<>0`:判断是否不等于0 - `>0`/`<0`:判断是否大于/小于0 #### 2. **内存访问细节** - **数据块结构** ```plaintext 地址 | 数据 ------------ 0 | 字节0 (DBB0) 1 | 字节1 (DBB1) 2 | DBW2低字节 (DBB2) 3 | DBW2高字节 (DBB3) ``` - `DBW2` 占用**连续两个字节**(地址2和3),按大端序存储。 - **重要规则** - 必须先使用`OPN DBx`打开数据块(如`OPN DB1`) - 未指定DB编号时,默认使用最后一次打开的DB。 #### 3. **常见问题排查** - **数据范围错误** `DBW`是**16位有符号整数**(范围:-32,768 ~ 32,767)。若实际值超范围,需改用`DBD`(32位)。 - **地址对齐问题** 字类型(`DBW`)必须从**偶数地址**开始(如2,4,6)。访问奇数地址(如`DBW3`)会导致编译错误。 - **未打开数据块** 若未执行`OPN DBx`,将触发运行时错误。 #### 4. **完整示例** ```stl // 打开数据块DB1 OPN DB1 // 检查DB1.DBW2是否等于0 L DBW 2 // 加载值到ACCU1 ==0 // 比较ACCU1 == 0? = "Tag_1" // 若为真,将结果赋给标签Tag_1 ``` > **调试建议**: > 在TIA Portal的**监控表**中监视`DB1.DBW2`的实时值,并检查状态字的`RLO`(逻辑运算结果)位确认比较结果[^1]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值