zoukankan      html  css  js  c++  java
  • 2017年天梯赛LV2题目汇总小结

    Ⅰ.L2-021 点赞狂魔---STL应用

    微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。
    
    输入格式:
    输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。
    
    输出格式:
    统计每个人点赞的不同标签的数量,找出数量最大的前3名,在一行中顺序输出他们的用户名,其间以1个空格分隔,且行末不得有多余空格。如果有并列,则输出标签出现次数平均值最小的那个,题目保证这样的用户没有并列。若不足3人,则用-补齐缺失,例如mike jenny -就表示只有2人。
    
    输入样例:
    5
    bob 11 101 102 103 104 105 106 107 108 108 107 107
    peter 8 1 2 3 4 3 2 5 1
    chris 12 1 2 3 4 5 6 7 8 9 1 2 3
    john 10 8 7 6 5 4 3 2 1 7 5
    jack 9 6 7 8 9 10 11 12 13 14
    输出样例:
    jack chris john
    
    

    思路:使用集合(自动去重) 统计每个人点赞不同博文的数量。输出前3个人,不足3人输出“-”

    #include<bits/stdc++.h>
    using namespace std;
    
    
    int n;
    set<int> se;
    
    struct node{
    	int size;
    	string name;
    	int aclSize;
    };
    node ans[105];
    
    bool cmp(node a,node b){
    	if(a.size == b.size){
    		return a.aclSize < b.aclSize;
    	}
    	return a.size > b.size;
    }
    
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		string name;
    		cin>>name;
    		ans[i].name = name;
    		int k;
    		cin>>k;
    		ans[i].aclSize = k;
    		for(int j=1;j<=k;j++){
    			int d;
    			cin>>d;
    			se.insert(d);
    		}
    		ans[i].size = se.size();
    		se.clear();
    	}
    	sort(ans+1,ans+n+1,cmp);
    	int first = 1;
    	for(int i=1;i<=3 && i<=n;i++){
    		if(first){
    			cout<<ans[i].name;
    			first = 0;
    		}else{
    			cout<<" "<<ans[i].name;
    		}
    	}
    	if(n<3){
    		for(int i=n+1;i<=3;i++){
    			cout<<" "<<"-";
    		}
    	}
    	return 0;
    } 
    

    Ⅱ.L2-022 重排链表--数组模拟链表

    给定一个单链表 L
    请编写程序将链表重新排列为 L
    例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。
    
    输入格式:
    每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。
    
    接下来有N行,每行格式为:
    
    Address Data Next
    其中Address是结点地址;Data是该结点保存的数据,为不超过10
    ​5
    ​​ 的正整数;Next是下一结点的地址。题目保证给出的链表上至少有两个结点。
    
    输出格式:
    对每个测试用例,顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。
    
    输入样例:
    00100 6
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 68237
    12309 2 33218
    输出样例:
    68237 6 00100
    00100 1 99999
    99999 5 12309
    12309 2 00000
    00000 4 33218
    33218 3 -1
    

    思路:结构体模拟链表,具体做法不太好表达,看代码吧
    转载至:https://blog.csdn.net/hy971216/article/details/80496917

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    
    const int maxn = 1e5;
    
    struct Node{
        int address;
        int key;
        int next;
        int num; //结点的最终位置下标 
    }node[maxn]; //存放数据 后面改变下标后也存放输出结果 
    
    bool vis[maxn];
    
    bool cmp(Node a,Node b){
        return a.num<b.num;
    }
    
    int main()
    {
        int head,n,a;
        scanf("%d%d",&head,&n);
        int k1=0,k2=0;
        for(int i=0;i<maxn;i++){
            node[i].num=2*maxn;//初始化 num为最大 
        }
        for(int i=0;i<n;i++){
            scanf("%d",&a);//地址作为下标 
            scanf("%d%d",&node[a].key,&node[a].next);
            node[a].address=a;
        }
        for(int i=head;i!=-1;i=node[i].next){
            if(!vis[abs(node[i].key)]){ //没有出现过当前结点的绝对值 就从下标0开始按顺序存放到结构体数组中 
                vis[abs(node[i].key)]=true;
                node[i].num=k1;
                k1++;
            }else{
                node[i].num=maxn+k2;//出现过 就从下标maxn开始存放  因为最大也就maxn个结点 
                k2++;
            }
        }
        sort(node,node+maxn,cmp);//按num排序
        int k=k1+k2;
        for(int i=0;i<k;i++){
            if(i!=k1-1&&i!=k-1){
                printf("%05d %d %05d
    ",node[i].address,node[i].key,node[i+1].address); // %05d输出5个长度整数 不足5为补0 
            }else{
                printf("%05d %d -1
    ",node[i].address,node[i].key);
            }
        }
        return 0;
    }
    
    

    Ⅲ.L2-023 图着色问题---图着色dfs、bfs、邻接点问题

    图着色问题是一个著名的NP完全问题。给定无向图G=(V,E),问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?
    
    但本题并不是要你解决这个着色问题,而是对给定的一种颜色分配,请你判断这是否是图着色问题的一个解。
    
    输入格式:
    输入在第一行给出3个整数V(0<V≤500)、E(≥0)和K(0<K≤V),分别是无向图的顶点数、边数、以及颜色数。顶点和颜色都从1到V编号。随后E行,每行给出一条边的两个端点的编号。在图的信息给出之后,给出了一个正整数N(≤20),是待检查的颜色分配方案的个数。随后N行,每行顺次给出V个顶点的颜色(第i个数字表示第i个顶点的颜色),数字间以空格分隔。题目保证给定的无向图是合法的(即不存在自回路和重边)。
    
    输出格式:
    对每种颜色分配方案,如果是图着色问题的一个解则输出Yes,否则输出No,每句占一行。
    
    输入样例:
    6 8 3
    2 1
    1 3
    4 6
    2 5
    2 4
    5 4
    5 6
    3 6
    4
    1 2 3 3 1 2
    4 5 6 6 4 5
    1 2 3 4 5 6
    2 3 4 2 3 4
    输出样例:
    Yes
    Yes
    No
    No
    

    思路:只需判断邻接点是否颜色相等,bfs和dfs或者直接暴力看邻接边的两端点。
    还有一些特殊样例:当k(颜色数) != 输入的颜色数 也不符合条件

    dfs做法 23分 wa了一个点:

    #include<bits/stdc++.h>
    using namespace std;
    
    vector<int> g[510];
    int v,e,k,n;
    set<int> se;
    int vis[510];
    int col[510];
    bool flag = true;
    
    void dfs(int x){
    	if(!flag)return;
    	vis[x] = 1;
    	int color = col[x];
    	for(int i=0;i<g[x].size();i++){
    		if(!vis[g[x][i]]){
    			if(color == col[g[x][i]])
    				flag = false;
    			else
    				dfs(g[x][i]);
    		} 
    	}
    }
    
    int main(){
    	cin>>v>>e>>k;
    	for(int i=1;i<=e;i++){
    		int d1,d2;
    		cin>>d1>>d2;
    		g[d1].push_back(d2);
    		g[d2].push_back(d1);
    	}
    	cin>>n;
    	while(n--){
    		memset(vis,0,sizeof(vis));
    		for(int i=1;i<=v;i++){
    			int d;
    			cin>>d;
    			se.insert(d);
    			col[i] = d;
    		}
    		if(se.size()!=k){
    			cout<<"No"<<endl;
    		}else{
    				flag = true;
    				for(int i=1;i<=v;i++){
    					if(!vis[i] && flag){
    						dfs(i);
    					}
    				} 
    				if(flag){
    					cout<<"Yes"<<endl;
    				}else{
    					cout<<"No"<<endl;
    				}
    			
    		}
    		se.clear();
    	}
    	return 0;
    }
    

    其他暴力做法—查看邻接矩阵中的 邻接边两端点颜色是否相等
    参考代码:https://blog.csdn.net/guoqingshuang/article/details/80575008

    Ⅳ.L2-024 部落--并查集

    在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
    
    输入格式:
    输入在第一行给出一个正整数N(≤104),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:
    
    K P[1] P[2] ⋯ P[K]
    
    其中K是小圈子里的人数,P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过10​4。
    
    之后一行给出一个非负整数Q(≤104),是查询次数。随后Q行,每行给出一对被查询的人的编号。
    
    输出格式:
    首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y,否则输出N。
    
    输入样例:
    4
    3 10 1 2
    2 3 4
    4 1 5 7 8
    3 9 6 4
    2
    10 5
    3 7
    输出样例:
    10 2
    Y
    N
    

    思路:并查集,同一部落的属于同一集合

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 10010;
    int n;
    int father[maxn];
    set<int> se;
    set<int> se2;
    
    //查找 
    int find(int x){
    	if(father[x]==x) return x;
    	return father[x]=find(father[x]);
    } 
    
    //合并 
    void unite(int x,int y){
    	x=find(x);
    	y=find(y);
    	if(x!=y)
    	father[x]=y;
    }
    
    //初始化 
    void init(){
    	for(int i=1;i<=maxn-5;i++){ //注意这里初始化 不能初始化成maxn  ----段错误有时也不提醒..大坑 
    		father[i] = i;
    	}
    }
    
    int main(){
    	cin>>n;
    	init();
    	for(int i=1;i<=n;i++){
    		int k;
    		cin>>k;
    		int d;
    		cin>>d;
    		se.insert(d);//se集合中加入第一个元素 
    		int fa = d;
    		for(int j=2;j<=k;j++){
    			cin>>d;
    			se.insert(d);
    			unite(fa,d);//合并 
    		}
    	}
        for(set<int>::iterator it = se.begin();it!=se.end();it++){
            se2.insert(find(*it));//se2集合查询 有多少个根(部落数量) 
        }
    	printf("%d %d
    ",se.size(),se2.size());
    	int q;
    	cin>>q;
    	while(q--){
    		int pa,pb;
    		cin>>pa>>pb;
    		pa = find(pa);
    		pb = find(pb);
    		if(pa==pb){
    			puts("Y");
    		}else{
    			puts("N");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    nodeJs小练习之爬取北京昌平区房价
    2016,加油,奋斗
    1339 字符串王国的种族
    1333 明信片和照片
    1316 你能知道这是几进制数?
    1309 简化版九宫格
    1295 爱翻译
    1288 幸运转盘(一)
    1287 孙武练兵
    1284 喜羊羊的新年礼物
  • 原文地址:https://www.cnblogs.com/fisherss/p/10608313.html
Copyright © 2011-2022 走看看