【算法笔记】 简单进制例题及详解与程序

1.进制转换

题目描述

请你编一程序实现两种不同进制之间的数据转换。

输入格式

输入数据共有三行,第一行是一个正整数,表示需要转换的数的进制n(2≤n≤16),第二行是一个n进制数,若n>10则用大写字母A~F表示数码10~15,并且该n进制数对应的十进制的值不超过1000000000,第三行也是一个正整数,表示转换之后的数的进制m(2≤m≤16)。

输出格式

输出仅一行,包含一个正整数,表示转换之后的m进制数。

样例数据

input
16
FF
2

output
11111111

数据规模与约定

保证2≤m,n≤16
2≤m,n≤16

时间限制:1s
1s

空间限制:256MB
256MB

大致思路:一般情况下,将初始的数据a进制转化成为十进制,再将十进制转化成为需要求的进制
1.将初始值转化为十进制:枚举初始的数s的每一位,答案为sum里,当我们枚举i时,sum=sum*a+s[i];
2.将10进制转换成b进制 设计数为tmp 存在数组a中 while (s) {a[++tmp]=s%b,b/=10;}若要输出则从tmp到1倒序输出即可
参考代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a,c,s=0,t=0;
    string ss,b;
    ss="0123456789ABCDEF";
    cin>>a;
    cin>>b;
    cin>>c; 
    for (int i=0;i<b.size();i++)
    if (b[i]>='0'&&b[i]<='9') s=int(b[i]-'0')+s*a;
    else s=int(b[i]-'A')+10+s*a;
    int ans[10000]={};
    while (s)
    {
        ans[++t]=s%c;
        s=s/c;
    }
    for (int i=t;i>=1;i--) cout<<ss[ans[i]];
    return 0;
}

2.16进制转8进制

这是一道十分玄学的题目.你或许会觉得可以和上面一题一样选则10进制作为中间进制,那么便会因为16进制过长从而到时至今只放不下然后爆炸,爆炸,爆炸了.
正确的方法是,以2进制作为中间进制,然后我们通过观察,16=2^4;8=2^3,必然有特殊的关系
16进制的每一位都代表4位二进制数,将每一位展开成二进制数即可
而每三位代表一位8进制,三位,三位地转成8进制即可 若一整串数字的长度不是单的倍数,则在前面补0,既方便程序运行,同时却对结果不会产生影响。
参考代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s,s2,s8;
    cin>>s;
    if (s[0]=='0')
    {
        cout<<0;
        return 0;
    }
    for (int i=0;i<s.size();i++)
    {
        if (s[i]=='0') s2+="0000";
        if (s[i]=='1') s2+="0001";
        if (s[i]=='2') s2+="0010";
        if (s[i]=='3') s2+="0011";
        if (s[i]=='4') s2+="0100";
        if (s[i]=='5') s2+="0101";
        if (s[i]=='6') s2+="0110";
        if (s[i]=='7') s2+="0111";
        if (s[i]=='8') s2+="1000";
        if (s[i]=='9') s2+="1001";
        if (s[i]=='A') s2+="1010";
        if (s[i]=='B') s2+="1011";
        if (s[i]=='C') s2+="1100";
        if (s[i]=='D') s2+="1101";
        if (s[i]=='E') s2+="1110";
        if (s[i]=='F') s2+="1111";  
    } //16->2
    if (s.size()%3)
        for (int i=1;i<=3-s.size()%3;i++) 
            s2='0'+s2;//补0
    for (int i=0;i<s2.size();i+=3)
    {
        string s22;
        s22=s2[i];
        s22=s22+s2[i+1];
        s22=s22+s2[i+2];
        if (s22=="000") s8+='0';
        if (s22=="001") s8+='1';
        if (s22=="010") s8+='2';
        if (s22=="011") s8+='3';
        if (s22=="100") s8+='4';
        if (s22=="101") s8+='5';
        if (s22=="110") s8+='6';
        if (s22=="111") s8+='7';
    }//2->8
    int j;
    for (j=0;j<s8.length();j++) if (s8[j]!='0') break;
    for (int i=j;i<s8.length();i++) cout<<s8[i];//Write
    return 0;
}

3.砝码称重

题目描述

一个天平,砝码分别为1g、3g、9g、27g、…6561g,每个砝码只有一个,要称重的物品放在天平的左侧,而砝码允许放在天平的左右两侧。已知一个物品的重量,问如何称重?试编程解决。

输入格式

一个重量N(1≤N≤9000)

输出格式

将所使用的砝码重量,按从大到小的顺序输出。其中与物品异侧的砝码用正号表示,与物品同侧的砝码用负号表示。(第一个砝码前的正号要省略)

样例数据

input
15

output
27-9-3

数据规模与约定

保证1≤N≤9000
1≤N≤9000

通过观察,这些数字全部是由3的倍数解决的,我们便可以考虑使用3进制进行实现,就以样例中的15为例:
15的三进制是:1 2 0 对应的数是9(3^2),3(3^1),1(3^0);说明要用一个质量为9的砝码,2个质量为3的砝码拼成15.但是由题意得,每一个砝码只有一个,但是可以减去这个砝码.因此我们可以的得到如下结论:
1.当对应的三进制为为1,则取
2.当对应的三进制为为0,则不去
3.当对应的三进制为为2,则向上取一个并减去这个.该方法策略证明:设这个重m,下一个为3m,本来是:2*m=3m;后来是:3m-m=2m;故相同.
在以15为例:枚举到第1位,即砝码为1g时不取;枚举到第2位,对应2,减去这个3g,下一位进1;枚举到第3位时,虽然只有1,但是前面进了1,所以变2,减去这个数9g,再往前进;枚举到第4位时,因为上一位进了1,所以取这个27g;故答案是27-9-3

#include<bits/stdc++.h>
using namespace std;
int n;
int ans[10000000]={};
int a[10000000]={};
int tmp=0,cnt=0; 
int main()
{
    cin>>n;
    while (n){a[++tmp]=n%3;n/=3;}//转成三进制
    tmp+=10; 
    for (int i=1;i<=tmp;i++)
    {
        if (a[i]==0) continue;//0表示不取
        if (a[i]==1) ans[++cnt]=pow(3,i-1);//1表示取一个
        if (a[i]==2) ans[++cnt]=-pow(3,i-1),a[i+1]++;//2则减一个再进1
        if (a[i]==3) a[i+1]++;//3则进1
    }
    for (int i=cnt;i;i--)
    {
        if (i!=cnt)
        {
            if (ans[i]>0) cout<<'+'<<ans[i];
                else cout<<ans[i];
        }
        else cout<<ans[cnt];//第一个不输出+号
    }
    return 0;
}

4.倒水

题目描述

一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子) 显然在某些情况下CC无法达到目标,比如N=3,K=1。此时CC会重新买一些新的瓶子(新瓶子容量无限,开始时有1升水),以到达目标。 现在CC想知道,最少需要买多少新瓶子才能达到目标呢?

输入格式

一行两个正整数, N,K(1<=N<=10 9
109
,K<=1000)。

输出格式

一个非负整数,表示最少需要买多少新瓶子。

样例数据

input1
3 1

output1
1

input2
13 2

output2
3

input3
1000000 5

output3
15808

通过观察,发现当前拥有的水的数量等于当前的二进制位,如3的二进制是11,显然,2并1再加1是2,显然,与二进制是相对应的.同样,加上的瓶数在最后所剩下的瓶数同样是等于原来的二进制加上对应数的新二进制数的1的数目,那么,我们就可以这么做题:
1.把这个数字转换成二进制
2.不断的在末尾+1,并统计,直至1

#include<bits/stdc++.h>
using namespace std;
int a[90000000]={},tmp=0; 
int main() 
{
    int n,k;
    cin>>n>>k;
    while (n){a[++tmp]=n%2,n/=2;}//转换2进制
    for (int ans=0;;ans++)
    {
        int sum=0;
        for (int i=1;i<=tmp;i++)
        {
            if (a[i]) sum++;
            if (sum>k) break;
        }
        if (sum<=k) 
        {
            cout<<ans;
            return 0;
        }//统计1并验证
        a[1]++;
        int p=1;
        while (a[p++]==2) a[p-1]=0,a[p]++;//加1并进位
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ronaldo7_zyb/article/details/80945104
今日推荐