2.1K尾相等数

本文探讨了一个数学问题,即找到一个大于1的自然数K,当K的幂次M和N(M>N)均大于或等于1000时,且它们的末尾三位数相等时,输出M+N的最小值。通过构造数组记录末尾三位数,利用循环和条件判断,最终得到结果。
/*
 *从键盘输入一个自然数K(K > 1),若存在自然数M和N(M > N),使得K^M和K^N均大于或等于
 *1000,且它们的末尾三位数相等,则称M 和 N是一对“K尾相等数”。请编一程序,输出M+N
 *值最小的K尾相等数。
 *对于一个数,它的幂是无穷无尽的,但是可以注意到末尾三位数只有1000个,也就是表明一定
 *会有重复的末尾三位数,当一个数的末尾三位数一定时,它的下一次幂的末尾三位数也一定了。
 *也就是表明当第一次重复出现大于等于1000的末尾三位数时,这就是我们要求的M和N。

 /

1.如果不考虑空间因素,构造1000数组,将每个i次数的i存入以它的尾数最后三位数x的n[x]中,如果发现n[x]已经存入,就可以将i与n[x]相加,得出结果。

2.因为只考虑尾数即可,为了防止溢出,可以将阶乘num 等效看成(1000+尾数)

#include <cstdlib>
#include <iostream>
using namespace std;

int main()
{
    double num = 0;
    int n[1000]={0};
    int i=1,m=0;
	int myn=0;
	while(1)
	{
		cin>>num;
		myn=num;
		if(num>10000)
			num=1000+myn%1000;
		for(i=0;i<1000;i++)
			n[i]=0;
		i=1;
		m=0;
		if(myn==1)
			break;
		while(myn<1000) // n>=1000
		{
			i++;
			myn=myn*num;
		}
		myn=myn%1000;
		n[myn]=i;
		i++;
		myn=myn*num;
		myn=myn%1000;
		while(n[myn]==0)
		{
			n[myn]=i;
			i++;
			myn=myn*num;
			myn=myn%1000;
		}
		m = n[myn]+i;
		cout<<m<<endl;
	}
    return 0;
}



1 伙伴系统 与边界标志法相比没有信息 分配内存块大小: 2n 由同一个内存块分割成的两个完全相等的内存块互为伙伴。 内存碎片化严重 回收时必须互为伙伴才能合并 不是伙伴,无法确定另一个内存块的边界 2 C语言实现 2.1 头文件 #pragma once #define M 16 typedef struct Word//定义节点 { struct Word* llink;//前驱 int tag;//0为空闲,1为占用 int kval;//k值,内存块的大小2^k struct Word* rlink;//后继 }Word, * Space; typedef struct HeadNode//定义顺序表节点 { int nodesize;//内存空间的大小 Word* first;//表映射内存空间的指针 Word* start;//记录内存池的首的地址 }FreeList[M+1];//顺序表 Space CreateMem();//创建内存池 void InitSqlist(FreeList& avail,Space p);//初始化顺序表 Word* AllocBuddy(FreeList& avail, int n);//分配内存单元 void Free(FreeList& avail, Space p);//回收内存 AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 2.2 创建内存池 #include"buddy.h" #include<stdio.h> #include <malloc.h> #include<math.h> #include <cassert> //Word* start;//定义全局变量记录内存池的开始地址,也可以在表的结构体中记录内存池的首的地址 Space CreateMem() { Word* pmem = (Word*)malloc((int)pow(2, M) * sizeof(Word));// 创建内存池 assert(pmem != NULL); pmem->llink = pmem; pmem->rlink = pmem; pmem->tag = 0; pmem->kval = M; //start = pmem; return pmem; } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2.3 初始化内存映射顺序表 void InitSqlist(FreeList& avail,Space p)//初始化内存映射表 { avail[0].start = p; for (int i = 0; i <= M; i++) { avail[i].first = NULL; avail[i].nodesize = 0; } int k = p->kval; avail[k].first = p; avail[k].nodesize = (int)pow(2, k); } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 2.4 分配内存单元 2.4.1 从内存映射表中删除该内存单元 static void Delete(FreeList& avail, Space p)//从对应表中删除该内存单元 { Word* front = p->llink; Word* rear = p->rlink; if (p == rear)//合并后,对应表内没有其他内存单元,将对应表置空 { avail[p->kval].first = NULL; } else//合并后,对应表内有其他内存单元,从表中删除该空间单元p { front->rlink = rear; rear->llink = front; avail[p->kval].first = rear; p->llink = p; p->rlink = p; } } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 2.4.2 分配内存单元,将剩余空间分裂 Word* AllocBuddy(FreeList& avail, int n)//分配内存单元 { Word* p = NULL;//分配的内存单元 for (int k = 0; k <= M; ++k) { if (k > M) { return NULL; } else if (avail[k].nodesize >= n && avail[k].first != NULL) { p = avail[k].first; Delete(avail, p);//从对应表中删除该内存单元 int i = 1; if (p->kval > 0 && avail[k].first == NULL)//将剩余空间分裂,插入表中 { while ((int)pow(2, k - i) >= n) { Word* pi = p + (int)pow(2, k - i); //pi = p + (int)pow(2, k - i); pi->rlink = pi; pi->llink = pi; pi->tag = 0; pi->kval = k - i; avail[k - i].first = pi; avail[k - i].nodesize = (int)pow(2, pi->kval); i++; } } p->llink = p; p->rlink = p; p->tag = 1; p->kval = k-(--i); break; } } return p; } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 2.5 回收内存 2.5.1 判断要回收的内存单元是左块还是右块 static Word* RorL(FreeList& avail,Space p)//判断左右内存块 { //int tmp = p - start;//计算p的相对地址 int tmp = p - avail[0].start; int flg = tmp % (int)pow(2, p->kval + 1); if (flg != 0)//p为右块,地址高 { return p - (int)pow(2, p->kval); } else//p为左块,地址低 { return p + (int)pow(2, p->kval); } } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 2.5.2 将内存单元和顺序表映射 static void Insert(FreeList& avail, Space p)//将内存单元和对应表映射 { if (avail[p->kval].first == NULL)//对应表为空,直接映射 { avail[p->kval].first = p; p->tag = 0; } else//对应表不为空,插在对应表指向内存单元的前面 { Word* q1 = avail[p->kval].first; Word* front = q1->llink; q1->llink = p; front->rlink = p; p->llink = front; p->rlink = q1; p->tag = 0; } } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2.5.3 判断顺序表是否为空 bool IsEmpty(FreeList& avail) { for (int i = 0; i <= M; i++) { if (avail[i].first != NULL) { return false; } } return true; } AI写代码 c 运行 1 2 3 4 5 6 7 8 9 10 11 2.5.4 判断伙伴,进行内存单元的回收合并 static void Free_mask(FreeList& avail, Space& p)//一次回收合并 { //形参p为实参的引用 Space pi = RorL(avail, p); if (pi->tag == 1)//伙伴不空闲 { Insert(avail, p);//看对应表情况,映射 } else if (pi->tag == 0 && pi->kval != p->kval)//伙伴不完整 { Insert(avail, p);//看对应表情况,映射 } else//伙伴空闲 { Delete(avail, pi);//从对应表中删除该内存单元 p->tag = 0; if (p > pi)//让p每次都作为左块 { p = pi; } p->kval++;//将p的k值++,用于判断合并后的伙伴 } } void Free(FreeList& avail, Space p)//回收内存单元 { if (!IsEmpty(avail)) { p->tag = 0; Space q = p; int k = p->kval; while (p->tag == 0 && p->kval == k)//当内存块空闲,且是完整的,进行合并 { Free_mask(avail, p); k++; } if (p->kval == M - 1)//当合并后的大小为内存池的一一半时 { q->kval--; avail[q->kval].first = NULL; q = q - (int)pow(2, q->kval); avail[M].first = q; q->llink = q; q->rlink = q; q->kval = M; q->tag = 0; } } else//小于一半大小,直接映射顺序表 { avail[p->kval].first = p; p->tag = 0; } } AI写代码 c 运行 用C语言编码实现伙伴系统的内存分配和回收
最新发布
11-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值