2021/5/15每周学习总结9

本周学习了二分法,理解了其通过不断取中间值来缩小搜索范围的逻辑。首先解决了一个将三个数组转换为两个数组并利用二分法寻找特定和的题目。接着,通过二分法解决了一个找零钱的背包问题,需要将小数转换为整数处理。这两题展示了二分法在降低时间复杂度上的优势。尽管感觉二分法比动态规划更直观,但实际应用中仍需深入理解和实践。
摘要由CSDN通过智能技术生成

每周学习总结
这周学习了二分法,主要是数学坐标逻辑,一直取中间值即可,刚开始学时感觉比dp有感觉,但是看了课件上的一些经典二分题发现并不简单,虽然逻辑上可以实现,但是要从题目写出二分,也不简单。
1简单二分

#include <iostream>
#include <algorithm>
using namespace std;
int a[505],b[505],c[505];
int sab[250005];
bool find( int a, int l , int h )
{
 if( l > h )
  return false;
 int mid = ( l + h ) / 2;
 if ( sab[mid] == a )
  return true;
 else if( sab[mid] > a)
  find ( a, l, mid-1);
 else
  find ( a, mid+1, h);
}
 int main()
{
 int l,n,m;
 int i,j,k;
 int s,sum,cnt = 1;
while( cin >> l >> n >> m )
 {
  for( i = 0; i < l; i++)
   cin >> a[i];
  for( i = 0; i < n; i++)
   cin >> b[i];
  for( i = 0; i < m; i++)
   cin >> c[i];
  for(k = 0, i = 0;i < l; i++)
   for( j = 0; j < n; j++)
    sab[k++] = a[i] + b[j];
  sort( sab, sab + k );
  cin >> s;
  cout << "Case " << cnt++ << ":\n";
for( i = 0; i < s; i++ )
  {
   cin >> sum;
   for( j = 0; j < m; j++)
       if ( find( sum - c[j] , 0 , k-1) )
     	break;
if( j == m)
    cout << "NO\n";
   else
    cout << "YES\n";
  }
 }
 return 0;
}

这道题是课件第一题,题目要求求出3个数组中找出3个数使其和等于一个定值
,此题有一个非常有趣的方法,就是先将3个数组转换为2个数组,然后再进行二分,这样处理大大减少了时间和复杂度,这里我仔细分析一下,这道题二分法的实现,

bool find( int a, int l , int h )
{
 if( l > h )
  return false;
 int mid = ( l + h ) / 2;
 if ( sab[mid] == a )
  return true;
 else if( sab[mid] > a)
  find ( a, l, mid-1);
 else
  find ( a, mid+1, h);
}

这是这道题二分的主要实现,传l和h分别是该数组的下限和上限,我们只需要判断sab((l+h)/2)是否与我们输入的值相等,如果相等,那么就找到了我们二分的点,如果没找到,那么讲上限或者下限缩小便可以了。
2找钱(背包)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
const int inf=0xfffffff;
typedef long long ll;
using namespace std;
const int maxn = 30010/5;
int a[11] = {1,2,4,10,20,40,100,200,400,1000,2000};
ll dp[maxn];
int main()
{
    double n;
    while(cin>>n&&n!=0.00){
        int nn = (int)(n *20 + 0.5);
  memset(dp, 0, sizeof(dp));
    dp[0] = 1;
    for(int i = 0; i < 11; ++i){
        for(int j = a[i]; j <=nn; ++j){
            dp[j] = dp[j] + dp[j - a[i]];
        }
    }
        printf("%6.2lf%17lld\n", n, dp[nn]);
    }
    return 0;
}

这道题和我上周做的一道背包题非常相似,可是这道题需要先把小数全部转换为整数,然后解题 dp[j] = dp[j] + dp[j - a[i]];此题关键的dp方程,可以看出来,基本和之前那道题别无二致,此题还有一个比较麻烦的地方就是输出格式问题,需要在宽度为6的字段中右对齐,这里我在网上找的用的printf的输出方法。
每周总结:
这周终于学习步入了正轨,我们也开始学习了二分,磨人的dp结束了,感觉二分并没有dp那么难找规律,也许是错觉。但是,不知不觉,这学期已经过去了一半,说实话过的太快了,有点没反应过来很多课都要结课了,但是感觉自己还是没能提升太多,可能是看题解看多了,唉,接下来的时间不能这样了,要好好学习,不能落下了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值