2011 problem A
/* 2011 problem A cin:n个数字(0,1000) ,0结束 cout:每位数加和排序输出(小->大) */ #include<cstdio> #include<vector> #include<algorithm> #include<iostream> using namespace std; vector<int> v; int add(int n){ int sum = 0; while(n/10>0||n%10!=0){ // 数字内部含有0 sum += n%10; n/=10; } return sum; } int main(){ int n; while(cin>>n){ if(n != 0){ v.push_back(add(n)); }else{ break; } } sort(v.begin(),v.end()); for(int i=0;i<v.size();i++){ cout<<v[i]<<" "; } cout<<endl; return 0; }
2011 problem B
/* 2011 problem B 给定矩阵的马鞍点。(在所在行最小,所在列最大) cin:行数,列数:m,n(1,100) 输入矩阵 cout:存在:i j a[i][j] 不存在:no 换行 4 4 9 7 6 8 20 26 22 25 28 36 25 30 12 4 2 6 */ #include<cstdio> #include<iostream> using namespace std; int main(){ int m,n; while(cin>>m>>n) { int a[m][n]; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ cin>>a[i][j]; } } int column = 0,row = 0,k; for(int i=0;i<m;i++) { // 找到第i行的最小值 int temp = a[i][0]; // cout<<"temp:"<<temp<<endl;; for(int j=0;j<n;j++){ if(temp > a[i][j]){ temp = a[i][j]; row = i; column = j; // cout<<i<<" "<<j<<" "<<temp<<endl; } } // 判断a[row][column]是否是column列的最大值 for(k=0;k<n;k++){ if(a[row][column]<a[k][column]){ // cout<<a[row][column]<<"not column max!"<<a[k][column]<<"k:"<<k<<endl; break; } if(k==n-1){ cout<<row<<" "<<column<<" "<<a[row][column]<<endl; } } } } return 0; }
2011 problem C
/* 2011 problem C 字符串压缩,连续的字符个数>=3个进行压缩。 aaaaabbbabaaaaaaaaaaaaaaaabbbb a5b3aba16b4 本题是要解压缩 cin:string 长度不超过50 cout: string 长度不超过100 换行 */ #include <cstdio> #include <cstring> #include<iostream> using namespace std; int main(){ char a[50]; int k=0,len=0,type; char c; cout<<"type:"<<endl; cin>>type; if(type==0){ // 解压 while(cin>>a){ for(int i=1;i<strlen(a);i++){ int cnt = 0,count=0; while(a[i]>='0'&&a[i]<='9'){ // 个数 cnt = cnt*10+a[i++]-'0'; // 字母后的数字提取 count++; // cnt的位数 } for(int j=0;j<cnt;j++){ cout<<a[i-count-1]; } if(cnt==0){// 字符后没有数字 cout<<a[i-1]; } } cout<<endl; } }else{ // 压缩 while(cin>>a){ for(int i=0;i<strlen(a);i++){ int cnt = 1; while(a[i]==a[i+1]){ // 记录连续的重复的元素 cnt++;i++; } if(cnt!=1){ cout<<a[i]<<cnt; }else{ cout<<a[i]; } } } cout<<endl; } return 0; }
2011 problem D
输入样例:
8 7 19 2 6 32 21 3 10
输出样例:
261
哈夫曼树:带权最短路径长度(WPL)最短的二叉树,也叫最优二叉树。
哈夫曼树的构建:将所有结点的权值按从小到大排序,先选择最小的两个结点作为树的初始叶子结点,二者权值之和作为根节点。然后将计算出来的和参与剩余节点权值的排序,继续选择最小的两个,以此类推。
WPL = (2+5)*3+7*2+13*1=48
哈夫曼编码:可以左子树标记0,右子树标记1,每一个结点所形成的01编码不能作为另外一个结点的前缀部分。
如上图:A:111 B:10 C:110 D:0
这样编码的话形成的01序列就可以辨认出具体是哪个结点,不会出现分辨不清的情况。
算法实现:
我们做题的时候不需要真的构建出哈夫曼树,只需要按照其思想求解出WPL即可 queue<int> name; name.front() 队首 name.back() 队尾 name.push(temp) 入队 name.pop() 出队 name.empty()检测是否为空 name.size() 队列长度 priority_queue :优先级递减的顺序排序,底层会随时自动调整顺序,最大的元素总在队首 priority_queue<int> q; priority_queue<int, vector<int>, less<int>> q; 同上面等价,less表示数字大的优先级大,greater表示数字小的优先级越大 q.top() 队首 其余方法一致 一开始我准备用数组来着,都是可行的,当数组的个数大于1时,进行循环,循环体内,先从大到小排序,将最后两个最小的元素加和赋值给temp,a[n-1]=0,a[n-2]=temp;WPL=temp
/* 2011 problem D 通信电文n个字符(4,30) 每个字符出现的频度Wi 根据权值构建哈夫曼树,计算带权路径长度 cin:n个 频度wi cout:带权路径长度 */ #include<iostream> #include<queue> using namespace std; priority_queue<int, vector<int>, greater<int> > q; // 注意一档要空格> > ,不能>> int main() { int n; int temp,x,y,WPL=0; cin>>n; // 所有的权值压入队列 for(int i=0;i<n;i++){ cin>>temp; q.push(temp); } // 当队列中个数大于1时进行操作 while(q.size()>1){ x=q.top(); q.pop(); y=q.top(); q.pop(); q.push(x+y); WPL+=x+y; } cout<<WPL; return 0; }