落谷P1008三连击(C++)

本文分享了一种解决落谷P1008问题的算法思路,通过对比个人实现与网上简洁代码,强调了使用数组标记数字出现的重要性,并记录了字符串与整数转换的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

落谷P1008

先贴我的代码:

      #include<iostream>
      #include<sstream>
      using namespace std;
      int main()
      {
      int a[3];
      int d,e,f;
      for(int i=1;i<4;i++)
      {
	    int n=0;
	    a[0]=i;
	    {
		for(int j=1;j<10;j++)
		{
		    n=0;
			a[1]=j;
			for(int k=1;k<10;k++)
			{
			    n=0;
				a[2]=k;
				d=a[0]*100+a[1]*10+a[2];
				e=d*2;
				f=d*3;
				if(f<998)
				 {
				   stringstream ss1,ss2,ss3;
				   string s,s1,s2,s3;
				 
				   ss1<<d;
				   ss1>>s1;
				 
				   ss2<<e;
				   ss2>>s2;
				  
				   ss3<<f;
				   ss3>>s3;
				   s=s1+s2+s3;
				   for(int q=0;q<9;q++)
				   {
				   	  for(int p=q+1;p<9;p++)
				   	  {
				   	  	if(s[q]-'0'==s[p]-'0'||s[p]-'0'==0||s[q]-'0'==0)
				   	  	{
							n=1;
							break;
						}
					  }
					  if(n==1)
					  break;
				   }//三个数无相等数字;
				   if(n==1)
				   continue;
			       else 
				   cout<<d<<" "<<e<<" "<<f<<endl;
				}
			}
		}
	}
}
}

思路很简单(虽然不够简洁) 但我第一次测试的时候未能通过
仔细看了后发现我犯了一个低级错误——把n 在循环外初始化;
说来惭愧 这种错误也不是第一次犯了 所以记录在此 谨防再犯!
另外再次提醒自己牢牢记住如!何!将!字符串!与!数值!相互转化!

#include<sstream>
{
   string s;
   int a;
   stringstream ss;
   ss<<s;
   ss>>a;//string to int;
   ss<<a;
   ss>>s;//int to string;
}

再贴网上找到的比较简洁的代码的关键部分:

{
  int a[10],b,c,d;
  int sum;
  for(b=123;b<330;b++)
  {
   sum=0;
   a[10]={0};
   a[b%10]=1;
   a[b/10%10]=1;
   a[b/100]=1;
   c=b*2;
   a[c%10]=1;
   a[c/10%10]=1;
   a[c/100]=1;
   d=b*3;
   a[d%10]=1;
   a[d/10%10]=1;
   a[d/100]=1;
   for(int i=1;i<10;i++)
   sum+=a[i];
   if(sum==9)
   cout<<b<<" "<<c<<" "<<d<<endl;
   }
return 0;
}

相比之下我的代码真是很笨拙、毫无技巧…
我完全没想过这种思路:引入数组并以数组值为1来代表对应数字出现了
一定要好好理解并记住

写在最后:
这是我的第一篇博客 这也是我决心学习算法的开始
路漫漫其修远兮
吾将上下而求索
现在很差 但一定会努力 使自己越来越好

数位 DP 是一个非常实用的算法,可以用于求解数字的各种性质。下面以计算 $[1,n]$ 中所有整数中数字 $d$ 出现次数的问题为例,介绍数位 DP 的实现方法。 假设我们要求出数字 $d$ 在 $[1,n]$ 中出现的次数,可以考虑将 $n$ 拆分成若干个数位,然后逐位统计 $d$ 出现的次数。具体地,我们可以使用 $f_{i,j,k}$ 表示考虑前 $i$ 位,当前数值为 $j$,是否达到上界 $k$ 的方案数。然后按照从高到低的顺序逐位进行统计。 状态转移方程为: $$ f_{i,j,k}=\sum_{p=0}^9 f_{i-1,p,k \ \&\&\ p=j} + [k=1]\times [j=d] \times (\text{数位 DP 的计算结果}) $$ 其中 $[x]$ 表示 Iverson 括号,当 $x$ 成立时为 $1$,否则为 $0$。第一项表示上一个数位传递下来的方案数,第二项表示当前数位对答案的贡献。 最终的答案为 $f_{\text{len}(n),0,1}$。 代码实现如下: ```cpp int f[20][10][2]; // f[i][j][k] 表示考虑到第 i 位,当前数字为 j,是否达到上界的方案数 int digit[20]; // 存储 n 的每一位数字 int dfs(int pos, int pre, bool limit, int d) { if (pos == -1) return 0; if (!limit && f[pos][pre][d] != -1) return f[pos][pre][d]; int up = limit ? digit[pos] : 9; int res = 0; for (int i = 0; i <= up; i++) { res += dfs(pos - 1, i, limit && (i == up), d) + (pre == d && i == d && !limit) ; } if (!limit) f[pos][pre][d] = res; return res; } int solve(int n, int d) { memset(f, -1, sizeof(f)); int pos = 0; while (n) { digit[pos++] = n % 10; n /= 10; } return dfs(pos - 1, 0, true, d); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值