清华大学07年复试上机题题解
2010-03-19 18:51
253 查看
第一题,质因数分解问题
由于数据规模不大,所以完全可以使用试除法,从2开始,每次找到一个因子后,nt /= i,并把试除起点重新设置为2,这样可以保证所有找到的因子不可能为合数.因此还避免了素数判定。
第二题,大数的二进制十进制互相转换
本题包括的两个子问题如下:
1.十进制大数串转换为二进制的问题,实际上是大数除以一个int型数据的问题,这比大数除大数的除法要简单得多,可以直接使用小学时学过的试除法,
即从高位开始,每位除以2,当然,要记得加上上一次除剩下来的结果。
2.二进制串转换为十进制。由于是大数,这里求2的幂的次数非常高,我的做法便是使用类似于求任意位阶乘的方法求出2的任意次幂,然后再用大数加法。这种做法是最原始的,但由于数学知识有限,只能如此了。
第三题,邮票面值问题
这个实际上是经典的0-1背包问题,状态转移方程基本上可以不做任何修改。
不过有个值得注意的问题是:
对于背包问题,如果只求最优解,而无需要恰好装满背包,则把全部初始化为0。
若要求刚好装满背包,则需要做如下初始化:
这种差别很微妙,需要认真体会一下。
由于数据规模不大,所以完全可以使用试除法,从2开始,每次找到一个因子后,nt /= i,并把试除起点重新设置为2,这样可以保证所有找到的因子不可能为合数.因此还避免了素数判定。
#include<iostream> using namespace std; int f(int n) { int nt = n; int cnt = 0; for(int i = 2; i <= nt;i++) if(!(nt%i)){ cout<<i<<" "; cnt++; nt = nt/i; i = 1; } cout<<endl; return cnt; } int main() { int n; while(cin>>n){ cout<<f(n)<<endl; } return 0; }
第二题,大数的二进制十进制互相转换
本题包括的两个子问题如下:
1.十进制大数串转换为二进制的问题,实际上是大数除以一个int型数据的问题,这比大数除大数的除法要简单得多,可以直接使用小学时学过的试除法,
即从高位开始,每位除以2,当然,要记得加上上一次除剩下来的结果。
2.二进制串转换为十进制。由于是大数,这里求2的幂的次数非常高,我的做法便是使用类似于求任意位阶乘的方法求出2的任意次幂,然后再用大数加法。这种做法是最原始的,但由于数学知识有限,只能如此了。
#include<iostream> using namespace std; const int N = 1000; const int M = 5000; char a ;//用于存储输入的初始数和最终结果 int b[M];//存储二进制位 int c ;//存储2^N次方的临时值 int alen,blen,clen; //本函数实现计算2^s次,并把结果与a相加存储于a void plus(int s) { memset(c,0,sizeof(c)); c[0]=1; clen = 1; //计算2^s次方,循环执行s次乘法 for(int i = 0;i < s;i++){ for(int j = 0;j < clen;j++) c[j] *= 2; //处理进位信息 for(int k = 0;(k < clen)||(c[k] != 0);k++){ c[k+1] += (c[k]/10); c[k] = c[k]%10; } clen = k; } int alen = (clen > alen?clen:alen)+1;//可能有进位,所以先把长度加1 //大数加法 for(int v = 0;v < alen;v++) { a[v] += c[v]; a[v+1] +=(a[v]/10); a[v] %= 10; } } void div2bit() { alen = strlen(a); for(int i = 0; i < alen;i++) a[i] = a[i]-'0'; int start = 0; blen = 0; while(a[alen-1] != 0 || start < alen){ //最末位的奇偶性便可决定模2的结果 if(a[alen-1]%2==1)b[blen++] = 1; else b[blen++] = 0; int r = 0;//上一次除2时的余 for(int j = start;j < alen;j++){ int tmp = r*10 + a[j]; a[j] = tmp/2; r = tmp%2; } //高位为0时可让下一次试除的起始位后移 if(a[start]==0)start++; } memset(a,0,sizeof(a)); for(int s = 0; s < blen;s++) if(b[s]!=0) plus(blen-s-1); //处理高位为0的情况 while(a[alen-1]==0)alen--; } int main() { while(cin>>a){ div2bit(); for(int j = alen-1;j >=0;j-- ) cout<<(a[j]-0); cout<<endl; } return 0; }
第三题,邮票面值问题
这个实际上是经典的0-1背包问题,状态转移方程基本上可以不做任何修改。
不过有个值得注意的问题是:
对于背包问题,如果只求最优解,而无需要恰好装满背包,则把全部初始化为0。
若要求刚好装满背包,则需要做如下初始化:
for(i = 0;i <= m;i++) c[i][0] = fail; //因为需要装满,所以不选就无法装满 //c[i][0] = fail; //若不需装满,0就是最优解 for(i = 0;i <= n;i++) c[0][i] = 0; //装满为零的都是有解的,就是选零张
这种差别很微妙,需要认真体会一下。
#include<iostream> using namespace std; #define fail 10000 const int M = 200; const int N = 20; int c[M] ;//c[i][j]表示面额为i,使用前j张面值时的最少张数 int v ; //每张邮票的面值 int m = 0,n = 0; int dp() { int i,j; for(i = 0;i <= m;i++) c[i][0] = fail; for(i = 0;i <= n;i++) c[0][i] = 0; int min ; for(i = 1; i <= m;i++){ for(j = 1; j <= n;j++ ){ if(i >= v[j]) { c[i][j] = c[i][j-1]; if(c[i][j] > c[i-v[j]][j-1]+1)c[i][j]=c[i-v[j]][j-1]+1; } else c[i][j] = c[i][j-1]; } } if(c[m] ==fail)c[m] = 0; return c[m] ; } int main() { memset(c,0,sizeof(c)); memset(v,0,sizeof(v)); while(cin>>m>>n){ for(int i = 1;i <= n;i++) cin>>v[i]; cout<<dp()<<endl; memset(c,0,sizeof(c)); memset(v,0,sizeof(v)); } }
相关文章推荐
- 清华大学 2011年研究生复试上机题 解题报告
- 清华大学2000年复试上机题 解题报告
- 清华大学2008年复试上机题 解题报告
- 查找学生信息——清华大学复试上机
- 清华大学2001年复试上机题 第一套 解题报告
- 清华大学2009年复试上机题 解题报告
- 【优先队列orVector】清华大学考研复试上机——成绩排序
- 剩下的树——清华大学复试上机
- 07年浙大复试上机题
- 北理07年复试上机之实现学生类并实现信息一些操作
- 清华大学2001年复试上机题 第二套 解题报告
- 清华大学2010年复试上机题 解题报告
- 二叉树遍历——清华大学复试上机
- 清华大学2002年复试上机题 第一套 解题报告
- 清华大学2011年复试上机题 解题报告
- 约数的个数——清华大学考研复试上机题
- 清华大学2002年复试上机题 第二套 解题报告
- 上海交大07年复试上机题分析
- 清华大学2003年复试上机题 解题报告
- 清华大学 2000年研究生复试上机题 解题报告