1124(map)+1125(排序,贪心)+1126(连通图)+1127(中序后序建树,层序遍历)

1124 Raffle for Weibo Followers (20 分)(map)

John got a full mark on PAT. He was so happy that he decided to hold a raffle(抽奖) for his followers on Weibo -- that is, he would select winners from every N followers who forwarded his post, and give away gifts. Now you are supposed to help him generate the list of winners.

Input Specification:

Each input file contains one test case. For each case, the first line gives three positive integers M (<= 1000), N and S, being the total number of forwards, the skip number of winners, and the index of the first winner (the indices start from 1). Then M lines follow, each gives the nickname (a nonempty string of no more than 20 characters, with no white space or return) of a follower who has forwarded John's post.

Note: it is possible that someone would forward more than once, but no one can win more than once. Hence if the current candidate of a winner has won before, we must skip him/her and consider the next one.

Output Specification:

For each case, print the list of winners in the same order as in the input, each nickname occupies a line. If there is no winner yet, print "Keep going..." instead.

Sample Input 1:

9 3 2
Imgonnawin!
PickMe
PickMeMeMeee
LookHere
Imgonnawin!
TryAgainAgain
TryAgainAgain
Imgonnawin!
TryAgainAgain

Sample Output 1:

PickMe
Imgonnawin!
TryAgainAgain

Sample Input 2:

2 3 5
Imgonnawin!
PickMe

Sample Output 2:

Keep going...

题目大意:

小明PAT考了满分,高兴之余决定发起微博转发抽奖活动,从转发的网友中按顺序每隔N个人就发出一个红包。请你编写程序帮助他确定中奖名单。注意:可能有人转发多次,但不能中奖多次。所以如果处于当前中奖位置的网友已经中过奖,则跳过他顺次取下一位。按照输入的顺序输出中奖名单,每个昵称占一行。如果没有人中奖,则输出“Keep going...”

分析:

用mapp存储当前用户有没有已经中奖过~当输入的时候,判断当前字符串是否已经在mapp中出现过,如果出现过就将s+1。每次判断i是否等于s,如果等于s且当前用户没有中过奖,就将它的名字输出,并且s = s + n~并将mapp[str]标记为1,且flag标记为true表示有过人中奖。最后flag如果依然是false说明要输出Keep going...

原文链接:https://blog.csdn.net/liuchuo/article/details/60467398

题解

这里没有理解清楚如果处于当前中奖位置的网友已经中过奖,则跳过他顺次取下一位的含义,看了柳神的题解之后才明白。我原先理解的意思是:每间隔n位取中奖者,如果取到这一位是已中过奖的则顺次下一位。而这里应该就是字面意思,每次输入网友的昵称时便判断是否以及中过奖,如果是则顺次下一位。

#include <bits/stdc++.h>

using namespace std;

int main()
{
#ifdef ONLINE_JUDGE
#else
    //freopen("1.txt", "r", stdin);
#endif
    int m,n,s;
    cin>>m>>n>>s;
    map<string,int> mp;
    string str;
    bool flag=false;
    for(int i=1;i<=m;i++){
        cin>>str;
		//如果处于当前中奖位置的网友已经中过奖,则跳过他顺次取下一位
        if(mp[str]==1) s+=1;
        if(i==s&&mp[str]==0){
            cout<<str<<endl;
            flag=true;
            mp[str]=1;
            s+=n;
        }
    }
    if(!flag){
        cout<<"Keep going..."<<endl;
    }
    return 0;
}

1125 Chain the Ropes (25 分)(排序,贪心)

Given some segments of rope, you are supposed to chain them into one rope. Each time you may only fold two segments into loops and chain them into one piece, as shown by the figure. The resulting chain will be treated as another segment of rope and can be folded again. After each chaining, the lengths of the original two segments will be halved.

Your job is to make the longest possible rope out of N given segments.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (2 <= N <= 104). Then N positive integer lengths of the segments are given in the next line, separated by spaces. All the integers are no more than 104.

Output Specification:

For each case, print in a line the length of the longest possible rope that can be made by the given segments. The result must be rounded to the nearest integer that is no greater than the maximum length.

Sample Input:

8
10 15 12 3 4 13 1 15

Sample Output:

14

题目大意:

给定一段一段的绳子,你需要把它们串成一条绳。每次串连的时候,是把两段绳子对折,再如下图所示套接在一起。这样得到的绳子又被当成是另一段绳子,可以再次对折去跟另一段绳子串连。每次串连后,原来两段绳子的长度就会减半。给定N段绳子的长度,你需要找出它们能串成的绳子的最大长度~

分析:

因为所有长度都要串在一起,每次都等于(旧的绳子长度+新的绳子长度)/2,所以越是早加入绳子长度中的段,越要对折的次数多,所以既然希望绳子长度是最长的,就必须让长的段对折次数尽可能的短。所以将所有段从小到大排序,然后从头到尾从小到大分别将每一段依次加入结绳的绳子中,最后得到的结果才会是最长的结果~
原文链接:https://blog.csdn.net/liuchuo/article/details/60467543

题解

#include <bits/stdc++.h>
using namespace std;
/*
1 3 4 10 12 13 15 15
1 2 4 10 12 13 15 15
3 10 12 13 15 15
6.5 12 13 15 15
9.25 13 15 15
11.125 15 15
13.0625 15
14.03125
*/
int main()
{
    int n;
    cin>>n;
    double num[n];
    for(int i=0;i<n;i++){
        cin>>num[i];
    }
    sort(num,num+n);
    for(int i=0;i<n-1;i++){
        num[i+1]=(num[i]+num[i+1])/2;
    }
    cout<<(int)num[n-1]<<endl;
	return 0;
}

1126 Eulerian Path (25 分)(连通图)

In graph theory, an Eulerian path is a path in a graph which visits every edge exactly once. Similarly, an Eulerian circuit is an Eulerian path which starts and ends on the same vertex. They were first discussed by Leonhard Euler while solving the famous Seven Bridges of Konigsberg problem in 1736. It has been proven that connected graphs with all vertices of even degree have an Eulerian circuit, and such graphs are called Eulerian. If there are exactly two vertices of odd degree, all Eulerian paths start at one of them and end at the other. A graph that has an Eulerian path but not an Eulerian circuit is called semi-Eulerian. (Cited from https://en.wikipedia.org/wiki/Eulerian_path)

Given an undirected graph, you are supposed to tell if it is Eulerian, semi-Eulerian, or non-Eulerian.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 numbers N (<= 500), and M, which are the total number of vertices, and the number of edges, respectively. Then M lines follow, each describes an edge by giving the two ends of the edge (the vertices are numbered from 1 to N).

Output Specification:

For each test case, first print in a line the degrees of the vertices in ascending order of their indices. Then in the next line print your conclusion about the graph -- either "Eulerian", "Semi-Eulerian", or "Non-Eulerian". Note that all the numbers in the first line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.

Sample Input 1:

7 12
5 7
1 2
1 3
2 3
2 4
3 4
5 2
7 6
6 3
4 5
6 4
5 6

Sample Output 1:

2 4 4 4 4 4 2
Eulerian

Sample Input 2:

6 10
1 2
1 3
2 3
2 4
3 4
5 2
6 3
4 5
6 4
5 6

Sample Output 2:

2 4 4 4 3 3
Semi-Eulerian

Sample Input 3:

5 8
1 2
2 5
5 4
4 1
1 3
3 2
3 4
5 3

Sample Output 3:

3 3 4 3 3
Non-Eulerian

题目大意:

如果一个连通图的所有结点的度都是偶数,那么它就是Eulerian,如果除了两个结点的度是奇数其他都是偶数,那么它就是Semi-Eulerian,否则就是Non-Eulerian~

分析:

用邻接表存储图,判断每个结点的度【也就是每个结点i的v[i].size()】是多少即可得到最终结果~注意:图必须是连通图,所以要用一个深搜判断一下连通性,从结点1开始深搜,如果最后发现统计的连通结点个数cnt != n说明是不是连通图,要输出Non-Eulerian~

原文链接:https://blog.csdn.net/liuchuo/article/details/60479835

题解


using namespace std;
vector<vector<int> > v;
vector<bool> visit;
int cnt=0;
void dfs(int index){
    visit[index]=true;
    cnt++;
    for(int i=0;i<v[index].size();i++){
        if(visit[v[index][i]]==false)
            dfs(v[index][i]);
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    //freopen("1.txt", "r", stdin);
#endif
    int n,m,a,b,even=0;
    cin>>n>>m;
    v.resize(n+1);
    visit.resize(n+1);
    for(int i=0;i<m;i++){
        cin>>a>>b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    for(int i=1;i<=n;i++){
        if(i!=1) cout<<" ";
        cout<<v[i].size();
        if(v[i].size()%2==0) even++;
    }
    cout<<endl;
    dfs(1);
    if(cnt==n&&even==n)
        cout<<"Eulerian"<<endl;
    else if(cnt==n&&even==n-2)
        cout<<"Semi-Eulerian"<<endl;
    else
        cout<<"Non-Eulerian"<<endl;
    return 0;
}

1127 ZigZagging on a Tree (30 分)(中序后序建树,层序遍历)

Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences. And it is a simple standard routine to print the numbers in level-order. However, if you think the problem is too simple, then you are too naive. This time you are supposed to print the numbers in "zigzagging order" -- that is, starting from the root, print the numbers level-by-level, alternating between left to right and right to left. For example, for the following tree you must output: 1 11 5 8 17 12 20 15.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<= 30), the total number of nodes in the binary tree. The second line gives the inorder sequence and the third line gives the postorder sequence. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the zigzagging sequence of the tree in a line. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

8
12 11 20 17 1 15 8 5
12 20 17 11 15 8 5 1
Sample Output:
1 11 5 8 17 12 20 15

题目大意:

给出一个树的中序和后序遍历结果,求它的Z字型层序遍历,也就是偶数层从右往左,奇数层从左往右遍历~

分析:

分为3步:

  1. 根据中序和后序建树 保存在tree二维数组中,比如:tree[i][0] = val表示post[i]的左孩子是post[val],tree[i][1] = val表示post[i]的右孩子是post[val]~
  2. 进行广度优先搜索,将树从根结点开始所有结点层序遍历,保存在result二维数组中,比如:result[i]保存第i层所有结点的序列~
  3. 进行z字型输出,根据当前层号的奇偶性分别从左往右、从右往左遍历输出~

实现

  1. dfs:因为post(后序)是按照左、右、根的顺序遍历的,所以从右往左,最右边的肯定是根结点~所以postRight是当前子树的根结点的下标,将它的赋值给index,并继续dfs tree[index][0]和tree[index][1]~
    根据post[postRight]的结点在in里面的下标位置i,可以得到i的左边是左子树,即inLeft 到 i - 1,右边是右子树:i + 1 到 inRight。而对于post来说,根据左子树的结点个数i - inLeft可以得到[postLeft, postLeft + (i - inLeft) - 1]是post中左子树的范围,[postLeft + (i - inLeft), postRight - 1]是post中右子树的范围~

  2. 广度优先搜索,采用队列q,q中保存的是node结点,node.index表示当前节点在post中的下标,node.depth表示当前结点在树中的层数~

  3. 当 i % 2 == 0的时候倒序输出,否则正序输出~

原文链接:https://blog.csdn.net/liuchuo/article/details/60580953

题解

#include <bits/stdc++.h>

using namespace std;
struct node
{
    int data,depth;
    node* lchild;
    node* rchild;
};
vector<int> in,post,result[35];
int deep=0;
node* create(int postL,int postR,int inL,int inR)
{
    if(postL>postR) return nullptr;
    node* root=new node;
    root->data=post[postR];
    int k;
    for(k=inL;k<=inR;k++)
        if(in[k]==post[postR]) break;
    int numLeft=k-inL;
    root->lchild=create(postL,postL+numLeft-1,inL,k-1);
    root->rchild=create(postL+numLeft,postR-1,k+1,inR);
    return root;
}
void BFS(node* root)
{
    //if(root==nullptr) return;
    queue<node*> q;
    root->depth=1;
    q.push(root);
    while(!q.empty()){
        node* now=q.front();
        q.pop();
        result[now->depth].push_back(now->data);
        deep=now->depth;
        if(now->lchild!=nullptr){
            now->lchild->depth=now->depth+1;
            q.push(now->lchild);
        }
        if(now->rchild!=nullptr){
            now->rchild->depth=now->depth+1;
            q.push(now->rchild);
        }
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    //freopen("1.txt", "r", stdin);
#endif
    int n;
    cin>>n;
    in.resize(n);post.resize(n);
    for(int i=0;i<=n-1;i++)
        cin>>in[i];
    for(int i=0;i<=n-1;i++)
        cin>>post[i];
    node* root=create(0,n-1,0,n-1);
    BFS(root);
    cout<<result[1][0];
    for(int i=2;i<=deep;i++){
        if(i%2==0){
            for(int j=0;j<result[i].size();j++){
                cout<<" "<<result[i][j];
            }
        }else{
            for(int j=result[i].size()-1;j>=0;j--){
                cout<<" "<<result[i][j];
            }
        }
    }
    return 0;
}
posted @ 2022-02-24 19:59  勇往直前的力量  阅读(25)  评论(0编辑  收藏  举报