pat(六)

1051——1060

1051[栈]

Pop Sequence

经典题目,给定入栈顺序,判断一个序列是不是出栈序列。

思路:

主循环是入栈的顺序,每次入栈一个,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[链表排序]

Linked List Sorting

思路:

可以发现,每个结点的值和地址是固定的,变得只是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]

Path of Equal Weight

在一棵树中从根开始遍历,找到叶子结点且路径权和等于给定的值。

思路:

从根开始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[散列表]

The Dominant Color

求出出现次数最多的数。

思路:

用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[排序]

The World’s Richest

思路:多阶段排序的问题已经遇到很多了,不再赘述。这里搜索用了最朴素的算法,还好过了~

//
// @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",&times,&age_i,&age_j);
        printf("Case #%d:\n",i+1);
        my_search(p,age_i,age_j,times);
    }
    return 0;
}

1056[队列]

Mice and Rice

分组比赛选第一,也是经典题目

思路:用个队列,把所有元素按比赛顺序进队列即可,然后每一组第一名在出队列后在重新进队列。这里假设一个组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[二进制索引树/树状数组]

Stack

此题主要求在一个栈中的中位数!要求必须用比较快的算法!

思路:一开始,我想着用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[进制转换]

A+B in Hogwarts

思路:非常简单的进制转换。

//
// @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[素数分解]

Prime Factors

思路:先筛选出素数表,然后从小到大一个一个判断即可。建立素数表的过程可以记下来

//
// @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[科学计数法]

Are They Equal

思路:令人绝望的字符串操作,本题会有输入前面有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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值