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\n",node[i].address,node[i].key,node[i+1].address); // %05d输出5个长度整数 不足5为补0 
        }else{
            printf("%05d %d -1\n",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\n",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;
}
posted @ 2019-03-27 16:12  fishers  阅读(355)  评论(0编辑  收藏  举报