pat(七)

1061——1070

1061[公共字符]

Dating

思路:这个题目中的公共字符相对简单的,它们的下标是一致的,所以直接同步遍历即可。

//
// @author prime on 2017/6/29.
//

#include <iostream>

using namespace std;

int main()
{
    string a,b,c,d;
    cin>>a>>b>>c>>d;
    auto len1=min(a.size(),b.size());
    auto len2=min(c.size(),d.size());
    int res[3];
    int next;
    for (int i=0;i<len1;++i)
    {
        if(a[i]==b[i]&&a[i]>='A'&&a[i]<='G')
        {
            res[0]=a[i]-'A';//一周内的第几天(0~6)
            next=i;
            break;
        }
    }
    for (int i=next+1;i<len1;i++)
        if(a[i]==b[i]&&(a[i]>='0'&&a[i]<='9'||a[i]>='A'&&a[i]<='N'))
        {
            if(a[i]>='0'&&a[i]<='9')
                res[1]=a[i]-'0';//几点
            else
                res[1]=a[i]-'A'+10;
            break;
        }
    for (int i=0;i<len2;++i)
    {
        if(c[i]==d[i]&&(c[i]>='A'&&c[i]<='Z'||c[i]>='a'&&c[i]<='z'))
        {
            res[2]=i;
            break;
        }
    }
    string week[]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
    cout<<week[res[0]]<<" ";
    printf("%02d:%02d",res[1],res[2]);//日期格式,各占2位
    return 0;
}

1062[多阶段排序]

Talent and Virtue

思路:经典套路,一遍过,不多说了。

//
// @author prime on 2017/6/29.
//
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct People
{
    int talent,virtue;
    int id;
};

bool cmp(const People&o1,const People&o2)
{
    if((o1.virtue+o1.talent)!=(o2.virtue+o2.talent))
        return (o1.virtue+o1.talent)>(o2.virtue+o2.talent);
    else
    {
        if(o1.virtue!=o2.virtue)
            return o1.virtue>o2.virtue;
        else
            return o1.id<o2.id;
    }
}

int main()
{
    int N,L,H;
    scanf("%d%d%d",&N,&L,&H);
    vector<People> sage,nobleman,foolman,smallman;
    for (int i=0;i<N;++i)
    {
        People tmp;
        scanf("%d%d%d",&tmp.id,&tmp.virtue,&tmp.talent);
        if(tmp.talent<L||tmp.virtue<L)
            continue;
        else if(tmp.virtue>=H&&tmp.talent>=H)
            sage.push_back(tmp);
        else if(tmp.virtue>=H&&tmp.talent<H)
            nobleman.push_back(tmp);
        else if(tmp.virtue>=tmp.talent)
            foolman.push_back(tmp);
        else if(tmp.talent>tmp.virtue)
            smallman.push_back(tmp);
    }
    sort(sage.begin(),sage.end(),cmp);
    sort(nobleman.begin(),nobleman.end(),cmp);
    sort(foolman.begin(),foolman.end(),cmp);
    sort(smallman.begin(),smallman.end(),cmp);
    printf("%lld\n",sage.size()+nobleman.size()+foolman.size()+smallman.size());
    for (auto &e:sage)
        printf("%08d %d %d\n",e.id,e.virtue,e.talent);
    for (auto &e:nobleman)
        printf("%08d %d %d\n",e.id,e.virtue,e.talent);
    for (auto &e:foolman)
        printf("%08d %d %d\n",e.id,e.virtue,e.talent);
    for (auto &e:smallman)
        printf("%08d %d %d\n",e.id,e.virtue,e.talent);
    return 0;
}

1063[交集和并集/STL]

Set Similarity

思路:直接把两个序列都放入集合中,题目中序列可能有重复,这就不用管了。然后遍历其中一个集合,不在另一个集合中的元素就nt++,否则nc++,这里nt就是并集,nc就是交集,所以一开始nc为0,nt为另一个集合大小。

//
// @author prime on 2017/6/29.
//

#include <iostream>
#include <vector>
#include <unordered_set>

using namespace std;

int main()
{
    int N;
    scanf("%d",&N);
    vector<unordered_set<int>> arr;
    for (int i=0;i<N;++i)
    {
        int M;
        scanf("%d",&M);
        unordered_set<int> s;
        for (int j=0,tmp;j<M;++j)
        {
            scanf("%d",&tmp);
            s.insert(tmp);
        }
        arr.push_back(s);
    }
    int K;
    scanf("%d",&K);
    for (int i=0;i<K;++i)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int nc=0,nt=arr[b-1].size();
        for (auto&e:arr[a-1])
        {
            if(arr[b-1].find(e)==arr[b-1].end())
                nt++;
            else
                nc++;
        }
        printf("%0.1f%\n",(100.0*nc)/nt);
    }
    return 0;
}

1064[完全BST树]

Complete Binary Search Tree

给你一个序列,构造一个完全BST树,输出其层序遍历的结果。

思路:1020思路相近,这里给出了一个序列,那么只要把它们从小到大排序即是中序序列了。这道题就变成了给出中序序列求出其层序序列。补充一下,n个结点的二叉树高度是 logn2+1

算法完全可以沿用1020的,只不过需要单独确定根节点的位置。也就是说,要计算左子树总共有几个结点,然后用start+结点数就是根节点的位置。

//
// @author prime on 2017/6/30.
//

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int tree[20000];

void pre_traversal(const vector<int>& in_order,int start,int end,int index)
{//index和以前一样,start是中序起点,end是中序的终点。
    if(start>end)
        return;
    int n = end - start + 1;//这棵子树一共n个结点
    int L=log(n)/log(2);//除去叶子层,一共有几层
    int num=n-(pow(2,L)-1);//叶子结点个数
    int root=start+(pow(2,L-1)-1)+min((double)num,pow(2,L-1));//根的左子树的最后一层可能满了也可能没满,所以需要用min确定到底有几个结点
    tree[index]=in_order[root];
    pre_traversal(in_order,start,root-1,2*index);
    pre_traversal(in_order,root+1,end,2*index+1);
} 


int main()
{
    int N;
    scanf("%d",&N);
    fill(tree,tree+20000,-1);
    vector<int> in_order(N);
    for (int i=0;i<N;++i)
        scanf("%d",&in_order[i]);
    sort(in_order.begin(),in_order.end());
    pre_traversal(in_order,0,N-1,1);
    int count=0;
    for (auto&e:tree)
    {
        if(e!=-1)
        {
            if(count==N-1)
                printf("%d",e);
            else
                printf("%d ",e);
            count++;
        }
        if(count==N)
            break;
    }
    return 0;
}

1065[大整数相加]

A+B and C (64bit)

给定abc判断是否a+b>c

思路:题目中说了abc本身不会溢出,但是相加可能会,所以不要用字符串存储它们了,直接根据溢出判断,比如a>0 b>0,a+b<=0了,毫无疑问,溢出了,a+b肯定比c大了。。

//
// @author prime on 2017/6/30.
//
#include <iostream>
using namespace std;

int main()
{
    int T;
    scanf("%d",&T);
    long long a,b,c,sum;
    for (int i=0;i<T;++i)
    {
        scanf("%lld %lld %lld",&a,&b,&c);
        sum=a+b;
        printf("Case #%d: ",i+1);
        if(a>0&&b>0)
        {
            if(sum>0&&sum<=c)
                printf("false\n");
            else
                printf("true\n");
        } else if(a<0&&b<0)
        {
            if(sum<0&&sum>c)
                printf("true\n");
            else
                printf("false\n");
        } else
        {
            if(sum<=c)
                printf("false\n");
            else
                printf("true\n");
        }
    }
    return 0;
}

1066[AVL树]

Root of AVL Tree

非常经典的AVL树的题目,多看看!

思路:下面一张图就是思路,Wikipedia太好了,可以彻底放弃百度了。

//
// @author prime on 2017/6/30.
//

#include <iostream>

using namespace std;

struct Node
{
    int val;
    Node *left,*right;
};

Node* Right_Rotation(Node*root)
{
    Node*pivot=root->left;
    root->left=pivot->right;
    pivot->right=root;
    return pivot;
}

Node* Left_Rotation(Node*root)
{
    Node*pivot=root->right;
    root->right=pivot->left;
    pivot->left=root;
    return pivot;
}

Node* Left_Right_Rotation(Node* root)
{
    root->left=Left_Rotation(root->left);
    return Right_Rotation(root);
}

Node* Right_Left_Rotation(Node* root)
{
    root->right=Right_Rotation(root->right);
    return Left_Rotation(root);
}

int getHeight(Node*root)
{
    if(root== nullptr)
        return 0;
    else
        return max(getHeight(root->left),getHeight(root->right))+1;
}

Node* insert(Node*root,int val)
{
    if(root== nullptr)
    {
        root=new Node;
        root->val=val;
        root->left=root->right= nullptr;
    }
    else if(val<root->val)
    {//插入左子树
        root->left=insert(root->left,val);
        if(getHeight(root->left)-getHeight(root->right)==2)
            root=val<root->left->val?Right_Rotation(root):Left_Right_Rotation(root);
    }
    else
    {//插入右子树
        root->right=insert(root->right,val);
        if(getHeight(root->left)-getHeight(root->right)==-2)
            root=val<root->right->val?Right_Left_Rotation(root):Left_Rotation(root);
    }
    return root;
}


void pre_order(Node*root)
{//debug用的,可以删除
    if(root== nullptr)
        return;
    else
    {
        printf("%d ",root->val);
        pre_order(root->left);
        pre_order(root->right);
    }
}

int main()
{
    int N;
    scanf("%d",&N);
    Node* root= nullptr;
    for (int i=0;i<N;++i)
    {
        int val;
        scanf("%d",&val);
        root=insert(root,val);
    }
    //pre_order(root);
    printf("%d",root->val);
    return 0;
}

1067[贪心]

Sort with Swap(0,*)

每次只能用0与其它数交换,最少几次让其有序?(从小到大)

思路:输入的数都在[0,n-1]之间,每次用0交换时分两种情况:0的下标就是0,此时0和第一个不在其位的数交换;否则 ,0和0所在位置的数交换位置。因为需要频繁查询位置,所以对输入的数建立一个数——>下标的映射关系,交换也是对它进行。其中,index指向第一个不在其位置上的数的下标,每次0在其位时,就和index交换,index是递增的,每次都能把index归位,利用index可以不用每次都遍历查找了。

//
// @author prime on 2017/7/1.
//

#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    int N;
    scanf("%d",&N);
    vector<int> pos(N);
    int total=0;//统计除了0有多少个数不在其位
    for (int i=0,a;i<N;++i)
    {
        scanf("%d",&a);
        pos[a]=i;
        if(a!=i&&a!=0)
            total++;
    }
    int index=1;//第一个不在原本位置上的数的下标
    int res=0;//需要交换的总次数
    while(total!=0)
    {
        if(pos[0]!=0)
        {//0在i位上,就把0和i的位置对换,这样i归位
            swap(pos[0],pos[pos[0]]);
            res++;
            total--;
        }
        else
        {
            for (;index<N;++index)
            {
                if(pos[index]!=index)
                    break;
            }
            swap(pos[index],pos[0]);
            res++;
        }
    }
    printf("%d",res);
    return 0;
}

1068[子集求和/0-1背包]

Find More Coins

思路:“见规死”的神话能不能破。。/(ㄒoㄒ)/~~。表面上子集求和,挺难得,不会。但是转换思路,可以把总金额变成背包容量,货币面值变成物品,其价值和重量相等。那么,就转换成0-1背包问题了。

由于需要打印具体货币,所以用了个二维数组保存过程。先把货币从大到小排序,这样最后构造解的时候才符合题意。

//
// @author prime on 2017/7/1.
//

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    int N,M;
    scanf("%d%d",&N,&M);
    vector<int> w(N);
    for (int i=0;i<N;++i)
        scanf("%d",&w[i]);
    int dp[N+1][M+1];//dp[i][j]从前i个商品中总重量不超过j的最大价值
    bool choice[N+1][M+1];//记录选择
    fill(choice[0],choice[0]+(N+1)*(M+1),false);
    fill(dp[0],dp[0]+M+1,0);
    sort(w.begin(),w.end(),greater<int>());
    for (int i=0;i<N;++i)
        for (int j=0;j<=M;j++)
        {
            if(j<w[i])
                dp[i+1][j]=dp[i][j];
            else
            {
                if(dp[i][j]>dp[i][j-w[i]]+w[i])
                {
                    dp[i+1][j]=dp[i][j];
                }
                else
                {
                    dp[i+1][j]=dp[i][j-w[i]]+w[i];
                    choice[i][j]=true;
                }
            }
        }
    if(dp[N][M]!=M)
        printf("No Solution");
    else
    {
        vector<int> res;
        int total=M,index=N;
        while(total!=0)
        {
            if(choice[index][total])
            {
                res.push_back(w[index]);
                total-=w[index];
            }
            index--;
        }
        for (int i=0;i<res.size();++i)
        {
            printf("%d",res[i]);
            if(i!=res.size()-1)
                printf(" ");
        }
    }
    return 0;
}

1069[string的使用]

The Black Hole of Numbers

需要注意输入可能为6174,此时也要按过程走一波。所以得用do-while

//
// @author prime on 2017/7/1.
//

#include <iostream>
#include <algorithm>

using namespace std;

void process(string num)
{
    string a,b;
    int ia,ib;
    num.insert(0,4-num.size(),'0');
    do
    {
        sort(num.begin(),num.end(),greater<char>());
        a=num;
        sort(num.begin(),num.end(),less<char>());
        b=num;
        if(a==b)
        {
            cout<<num<<" - "<<num<<" = 0000";
            break;
        }
        ia=stoi(a);
        ib=stoi(b);
        num=to_string(ia-ib);
        num.insert(0,4-num.size(),'0');
        cout<<a<<" - "<<b<<" = "<<num<<endl;
    }while(num!="6174");
}


int main()
{
    string num,a,b;
    cin>>num;
    process(num);
    return 0;
}

1070[最大利润/贪心]

Mooncake

思路:按最高利润排序即可,优先卖高利润的月饼,没毛病。

//
// @author prime on 2017/7/1.
//

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Mooncake
{
    double inventory;
    double price;
    double rate;//性价比
};

bool cmp(const Mooncake&o1,const Mooncake&o2)
{
    return o1.rate>o2.rate;
}

int main()
{
    int N,D;
    scanf("%d%d",&N,&D);
    vector<Mooncake> s(N);
    for (int i=0;i<N;i++)
    {
        scanf("%lf",&s[i].inventory);
    }
    for (int i=0;i<N;++i)
    {
        scanf("%lf",&s[i].price);
        s[i].rate=s[i].price/s[i].inventory;
    }
    sort(s.begin(),s.end(),cmp);
    double total_profit=0;
    for (int i=0;i<N;++i)
    {
        if(s[i].inventory>D)
        {
            total_profit+=D*s[i].rate;
            break;
        }
        else
        {
            D-=s[i].inventory;
            total_profit+=s[i].price;
        }
    }
    printf("%.2lf",total_profit);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值