1051——1060
1051[栈]
经典题目,给定入栈顺序,判断一个序列是不是出栈序列。
思路:
主循环是入栈的顺序,每次入栈一个,current指向下一个待判定的元素,如果current指向元素和栈顶元素相等即匹配成功,则弹栈。如果栈溢出,则返回false;否则看最后current是否等于N。
//
// @author prime on 2017/6/26.
//
#include <iostream>
#include <deque>
#include <vector>
using namespace std;
int M,N,K;
bool check(vector<int> &s)
{
// bool flag=true;
deque<int> stack;
int current=0;
for (int i=1;i<=N;++i)//将1~N序列依次进栈
{
stack.push_back(i);
if(stack.size()>M)
{
return false;
}
while(!stack.empty()&&stack.back()==s[current])
{
stack.pop_back();
current++;
}
}
return current==N;//等于N说明都匹配了,否则说明未匹配完全且栈未溢出
}
int main()
{
scanf("%d%d%d",&M,&N,&K);
vector<int> a(N);
for(int i=0;i<K;++i)
{
for (int j=0;j<N;++j)
{
scanf("%d",&a[j]);
}
if(check(a))
{
printf("YES\n");
} else
printf("NO\n");
}
return 0;
}
1052[链表排序]
思路:
可以发现,每个结点的值和地址是固定的,变得只是next指针,所以只需要把链表按照key排序,然后输出即可(next就是下一个的起始地址)。
这道题卡输入,输入的结点可能有的不在链表中,所以要剔除。而且,没有结点时候也要特别输出。另外,这里排序完不要再求next了,直接用下一个元素的地址即可,能少写就少写!
//
// @author prime on 2017/6/26.
//
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Node
{
int addr;
int val;
int next;
};
bool cmp(const Node&o1,const Node& o2)
{
return o1.val<o2.val;
}
int main()
{
int N,start;
scanf("%d %d",&N,&start);
vector<Node> s(100001);
for (int i=0;i<N;++i)
{
int addr;
scanf("%d",&addr);
scanf("%d %d",&s[addr].val,&s[addr].next);
s[addr].addr=addr;
}
vector<Node> res;
for(int point=start;point!=-1;point=s[point].next)
{
res.push_back(s[point]);
}
sort(res.begin(),res.end(),cmp);
if(res.size()>0)
printf("%d %05d\n",res.size(),res[0].addr);
else
printf("0 -1\n");
for (int i=0;i<res.size();++i)
{
if(i==res.size()-1)
{
printf("%05d %d %d",res[i].addr,res[i].val,-1);
}
else
{
printf("%05d %d %05d\n",res[i].addr,res[i].val,res[i+1].addr);
}
}
return 0;
}
1053[DFS]
在一棵树中从根开始遍历,找到叶子结点且路径权和等于给定的值。
思路:
从根开始DFS即可,和以前的图论Dijkstra后的DFS很像,不过为了提高效率,增加剪枝条件。题目要求路径非递减排序,这里可以先求出路径后排序;也可以直接在输入时,按权值从大到小排序,这样DFS后的顺序就满足题意了。
//
// @author prime on 2017/6/26.
//
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
vector<int> tree[101];
vector<int> weight;
vector<vector<int>> res;
vector<int> tmp_path;
int N,M,S;
int total_weight=0;
/*bool cmp(const vector<int> &o1,const vector<int> &o2)
{
auto end=min(o1.size(),o2.size());
for (int i=0;i<end;++i)
{
if(o1[i]>o2[i])
return true;
else if(o1[i]<o2[i])
return false;
else
continue;
}
return false;//不知道为什么,不加这个就过不去最后一个用例,如果全部相等,true意味着翻转,false意味着和插入一样的顺序。
}*/
void DFS(int root)
{
tmp_path.push_back(weight[root]);
total_weight+=weight[root];
if(total_weight>S)//提前剪枝,也可以不加这个,然后在下面的到达根节点语句块中手动求和。
goto next;
if(tree[root].empty())
{//已到达根节点
if(total_weight==S)
res.push_back(tmp_path);
}
else
{
for (auto e:tree[root])
DFS(e);
}
next:
tmp_path.pop_back();
total_weight-=weight[root];
}
bool cmp(const int &o1,const int &o2)
{
return weight[o1]>weight[o2];
}
int main()
{
scanf("%d%d%d",&N,&M,&S);
weight.resize(N);
for (int i=0;i<N;++i)
scanf("%d",&weight[i]);
for (int i=0;i<M;++i)
{
int id,k,child;
scanf("%d%d",&id,&k);
for (int j=0;j<k;++j)
{
scanf("%d",&child);
tree[id].push_back(child);
}
sort(tree[id].begin(),tree[id].end(),cmp);
}
DFS(0);
//sort(res.begin(),res.end(),cmp);
for(auto & arr:res)
{
for (int i=0;i<arr.size();++i)
{
if(i!=arr.size()-1)
printf("%d ",arr[i]);
else
printf("%d",arr[i]);
}
printf("\n");
}
return 0;
}
1054[散列表]
求出出现次数最多的数。
思路:
用hashtable统计每个数字出现次数然后找到最多的即可。
//
// @author prime on 2017/6/26.
//
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
int M,N;
int color;
unordered_map<int,int> dict;
int max_p=-1,point=0;
scanf("%d%d",&M,&N);
for (int i=0;i<N;++i)
for (int j=0;j<M;j++)
{
scanf("%d",&color);
if(dict.find(color)==dict.end())
{
dict[color]=1;
} else
{
dict[color]++;
}
if(dict[color]>M*N/2&&dict[color]>max_p)
{
max_p=dict[color];
point=color;
}
}
printf("%d",point);
return 0;
}
1055[排序]
思路:多阶段排序的问题已经遇到很多了,不再赘述。这里搜索用了最朴素的算法,还好过了~
//
// @author prime on 2017/6/27.
//
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct People
{
char name[9];
int age,worth;
};
void my_search(const vector<People> &p,int age_i,int age_j,int times)
{
int count=0;
for (auto& e:p)
{
if(count==times)
break;
else if(e.age>=age_i&&e.age<=age_j)
{
printf("%s %d %d\n",e.name,e.age,e.worth);
count++;
} else
continue;
}
if(count==0)
printf("None\n");
}
bool cmp(const People&o1,const People&o2)
{
if(o1.worth!=o2.worth)
return o1.worth>o2.worth;
else if(o1.age!=o2.age)
return o1.age<o2.age;
else
return strcmp(o1.name,o2.name)<0;
}
int main()
{
int N,K;
scanf("%d%d",&N,&K);
vector<People> p(N);
for (int i=0;i<N;++i)
{
scanf("%s %d %d",p[i].name,&p[i].age,&p[i].worth);
}
sort(p.begin(),p.end(),cmp);
for (int i=0;i<K;++i)
{
int times,age_i,age_j;
scanf("%d%d%d",×,&age_i,&age_j);
printf("Case #%d:\n",i+1);
my_search(p,age_i,age_j,times);
}
return 0;
}
1056[队列]
分组比赛选第一,也是经典题目
思路:用个队列,把所有元素按比赛顺序进队列即可,然后每一组第一名在出队列后在重新进队列。这里假设一个组group个人,那么除了第一之外其它人都是第group+1名。一开始题目输入理解错了,第二行是每个参赛者重量,第三行的序号排列顺序就是比赛顺序,而号码代表第二行第几个老鼠。mmp
//
// @author prime on 2017/6/27.
//
#include <iostream>
#include <vector>
#include <algorithm>
#include <deque>
using namespace std;
struct Mouse
{
int input_order;
int index;//参赛顺序
int weight;
int rank;
};
bool cmp(const Mouse&o1,const Mouse&o2)
{
return o1.input_order<o2.input_order;
}
int main()
{
int Np,Ng;
scanf("%d%d",&Np,&Ng);
vector<int> we(Np);
vector<Mouse> m(Np);
for (int i=0;i<Np;++i)
{
scanf("%d",&we[i]);
}
for (int i=0,num;i<Np;++i)
{
scanf("%d",&num);
m[i].weight=we[num];
m[i].input_order=num;
m[i].index=i;
}
deque<Mouse> q;
for (int i=0;i<Np;++i)
q.push_back(m[i]);
while(!q.empty())
{
int len=q.size();
if(len==1)
{
m[q[0].index].rank=1;
break;
}
int group=len/Ng;
if(len%Ng!=0)
group++;//一共需要分成几组
int count=0;//每一小组人的计数
int max_weight=-1;
int point=-1;//指向每个小组最重的那个
for (int i=0;i<len;++i)
{
Mouse tmp=q[0];
m[tmp.index].rank=group+1;
q.pop_front();
count++;
if(tmp.weight>max_weight)
{
max_weight=tmp.weight;
point=tmp.index;
}
if(count==Ng||i==len-1)
{//小组进行完或者最后一个小组进行完
q.push_back(m[point]);
count=0;
max_weight=-1;
point=-1;
}
}
}
sort(m.begin(),m.end(),cmp);
for (int i=0;i<m.size();++i)
{
if(i!=m.size()-1)
printf("%d ",m[i].rank);
else
printf("%d",m[i].rank);
}
return 0;
}
1057[二进制索引树/树状数组]
此题主要求在一个栈中的中位数!要求必须用比较快的算法!
思路:一开始,我想着用map记录每个元素出现的次数,然后求中位数时从最小的开始累加出现次数,大于等于(size+1)/2为止。思路是对的,但是效率不够,超时了。于是需要一个更高级的数据结构——二进制索引树。这个数据结构详情见另一篇博客。
//
// @author prime on 2017/6/27.
//
#include <iostream>
#include <deque>
using namespace std;
const int maxn=100002;
int tree[maxn];
deque<int> stack;
int lowbit(int v)
{
return v&(-v);
}
int read(int idx)
{
int sum=0;
while (idx>0)
{
sum+=tree[idx];
idx-=lowbit(idx);
}
return sum;
}
void update(int idx,int val)
{
while(idx<=maxn-1)
{
tree[idx]+=val;
idx+=lowbit(idx);
}
}
void PeekMedian()
{
int left=1,right=maxn-1,mid,k=(stack.size()+1)/2;
while(left < right) {//注意这里二分法的变形,大于或等于都满足题意退出循环。
mid = (left + right) / 2;
if(read(mid) >= k)
right = mid;
else
left = mid + 1;
}
printf("%d\n", left);
}
int main()
{
int N;
char op[12];
scanf("%d",&N);
for (int i=0;i<N;++i)
{
scanf("%s",op);
if(op[1]=='o')
{//pop
if(stack.empty())
printf("Invalid\n");
else
{
printf("%d\n",stack.back());
update(stack.back(),-1);
stack.pop_back();
}
} else if(op[1]=='u')
{
int v;
scanf("%d",&v);
stack.push_back(v);
update(v,1);
}
else
{
if(!stack.empty())
PeekMedian();
else
printf("Invalid\n");
}
}
return 0;
}
1058[进制转换]
思路:非常简单的进制转换。
//
// @author prime on 2017/6/28.
//
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int G1,S1,K1,G2,S2,K2;
scanf("%d.%d.%d",&G1,&S1,&K1);
scanf("%d.%d.%d",&G2,&S2,&K2);
G1+=G2;S1+=S2;K1+=K2;
S1+=K1/29;K1%=29;
G1+=S1/17;S1%=17;
printf("%d.%d.%d",G1,S1,K1);
return 0;
}
1059[素数分解]
思路:先筛选出素数表,然后从小到大一个一个判断即可。建立素数表的过程可以记下来
//
// @author prime on 2017/6/28.
//
#include <iostream>
#include <vector>
using namespace std;
vector<bool> table(500000, true);
int main()
{
for (int i=2;i*i<500000;i++)//埃氏筛选法——简化版
for (int j=2;i*j<500000;j++)
table[i*j]= false;
long int a;
scanf("%ld",&a);
printf("%ld=",a);
if(a==1)
{
printf("1");
}
bool first=true,valid;
for (int i=2;a>=2;++i)
{
int exponent=0;valid= false;
while(table[i]&&a%i==0)
{
exponent++;
a/=i;
valid=true;
}
/*if(first)
{
if(exponent==1)
{
printf("%d",i);
first= false;//注意,这里first不能放在外边,不然第一个如果不满足题意,first也被重置了!!!坑苦了我
}
else if(exponent>=2)
{
printf("%d^%d",i,exponent);
first= false;
}
}
else
{
if(exponent==1)
{
printf("*%d",i);
}
else if(exponent>=2)
{
printf("*%d^%d",i,exponent);
}
}*/
if(valid)//表示i是其中一项
{
if(first)//第一项特殊处理
{
printf("%d",i);
first= false;
}
else
printf("*%d",i);
}
if(exponent>=2)
printf("^%d",exponent);
}
return 0;
}
1060[科学计数法]
思路:令人绝望的字符串操作,本题会有输入前面有0,以及输入为0的情况,都需要特别处理,还有虽然题目说有效位不超过100位,但tm有0就得把数组开大点,反正不要钱,,,这道题值得复习时好好看看!
//
// @author prime on 2017/6/28.
//
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int N;
char a[10000],b[10000];
scanf("%d",&N);
scanf("%s %s",a,b);
int dig_a=strlen(a),dig_b=strlen(b);//a和b小数点的位置
int start_a=0,start_b=0;//a和b中第一个非0数字所在位置
for (int i=0;i<strlen(a);i++)
{
if(a[i]=='.')
{
dig_a=i;
break;
}
}
for (int j=0;j<strlen(b);j++)
if(b[j]=='.')
{
dig_b=j;
break;
}
while(a[start_a]=='0'||a[start_a]=='.') start_a++;
while(b[start_b]=='0'||b[start_b]=='.') start_b++;
int exponent_a,exponent_b;
if(start_a==strlen(a))
exponent_a=0;
else
{
if(dig_a>=start_a)
exponent_a=dig_a-start_a;
else
exponent_a=dig_a-start_a+1;
}
if(start_b==strlen(b))
exponent_b=0;
else
{
if(dig_b>=start_b)
exponent_b=dig_b-start_b;
else
exponent_b=dig_b-start_b+1;
}
char res_a[101],res_b[101];
int count_a=0,count_b=0;
while(count_a<N)
{
if(start_a<strlen(a)&&a[start_a]!='.')
res_a[count_a++]=a[start_a];
else if(start_a>=strlen(a))
res_a[count_a++]='0';
start_a++;
}
while(count_b<N)
{
if(start_b<strlen(b)&&b[start_b]!='.')
res_b[count_b++]=b[start_b];
else if(start_b>=strlen(b))
res_b[count_b++]='0';
start_b++;
}
if(strcmp(res_a,res_b)==0&&exponent_a==exponent_b)
{
printf("YES 0.%s*10^%d",res_a,exponent_a);
}
else
{
printf("NO 0.%s*10^%d 0.%s*10^%d",res_a,exponent_a,res_b,exponent_b);
}
return 0;
}