L2-021. 点赞狂魔
微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。
输入格式:
输入在第一行给出一个正整数N(<=100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name K F1 ... FK”,其中 Name 是不超过8个英文小写字母的非空用户名,1<=K<=1000,Fi(i=1, ..., K)是特性标签的编号,我们将所有特性标签从1到107编号。数字间以空格分隔。
输出格式:
统计每个人点赞的不同标签的数量,找出数量最大的前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
用set去重然后排序就好了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
#define INF 100000000
typedef pair<int, int> P;
#define N 100
const int mod = 10007;
struct person{
string name;
set<int> s;
double ave;
bool operator < (const person & b) const{
if(s.size() != b.s.size())
return s.size() > b.s.size();
else
return ave < b.ave;
}
};
person ans[N];
int main()
{
int n, k, tmp;
scanf("%d", &n);
for(int i = 0; i < n; i++){
cin >> ans[i].name >> k;
for(int j = 0; j < k; j++){
scanf("%d", &tmp);
ans[i].s.insert(tmp);
}
ans[i].ave = 1.0 * k / ans[i].s.size();
}
sort(ans, ans + n);
if(n >= 3){
cout << ans[0].name << ' ' << ans[1].name << ' ' << ans[2].name << endl;
}else if(n == 2){
cout << ans[0].name << ' ' << ans[1].name << " -\n";
}else if(n == 1){
cout << ans[0].name << " - -\n";
}else{
cout << "- - -\n";
}
return 0;
}
7-10 功夫传人(25 分)
一门武功能否传承久远并被发扬光大,是要看缘分的。一般来说,师傅传授给徒弟的武功总要打个折扣,于是越往后传,弟子们的功夫就越弱…… 直到某一支的某一代突然出现一个天分特别高的弟子(或者是吃到了灵丹、挖到了特别的秘笈),会将功夫的威力一下子放大N倍 —— 我们称这种弟子为“得道者”。
这里我们来考察某一位祖师爷门下的徒子徒孙家谱:假设家谱中的每个人只有1位师傅(除了祖师爷没有师傅);每位师傅可以带很多徒弟;并且假设辈分严格有序,即祖师爷这门武功的每个第i
代传人只能在第i-1
代传人中拜1个师傅。我们假设已知祖师爷的功力值为Z
,每向下传承一代,就会减弱r%
,除非某一代弟子得道。现给出师门谱系关系,要求你算出所有得道者的功力总值。
输入格式:
输入在第一行给出3个正整数,分别是:N(≤105)——整个师门的总人数(于是每个人从0到N−1编号,祖师爷的编号为0);Z——祖师爷的功力值(不一定是整数,但起码是正数);r ——每传一代功夫所打的折扣百分比值(不超过100的正数)。接下来有N行,第i行(i=0,⋯,N−1)描述编号为i的人所传的徒弟,格式为:
Ki ID[1] ID[2] ⋯ ID[Ki]
其中Ki是徒弟的个数,后面跟的是各位徒弟的编号,数字间以空格间隔。Ki为零表示这是一位得道者,这时后面跟的一个数字表示其武功被放大的倍数。
输出格式:
在一行中输出所有得道者的功力总值,只保留其整数部分。题目保证输入和正确的输出都不超过1010。
输入样例:
10 18.0 1.00
3 2 3 5
1 9
1 4
1 7
0 7
2 6 1
1 8
0 9
0 4
0 3
输出样例:
404
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
#define INF 100000000
typedef pair<int, int> P;
#define N 100001
const int mod = 10007;
vector<int> mp[N];
double ans, g[N], z, r;
int n, m, k, tmp;
int dai[N];
void dfs(int x, int d)
{
for(int i = 0; i < mp[x].size(); i++){
int t = mp[x][i];
dai[t] = d;
if(g[t]<= eps)
dfs(t, d + 1);
}
}
int main()
{
scanf("%d%lf%lf", &n, &z, &r);
r = (100.0 - r) * 0.01;
for(int i = 0; i < n; i++){
scanf("%d", &k);
if(k == 0){
scanf("%lf", &g[i]);
continue;
}
while(k--){
scanf("%d", &tmp);
mp[i].push_back(tmp);
}
}
dfs(0, 1);
for(int i = 0; i< n; i++){
if(g[i] >= eps){
ans += g[i] * pow(r, dai[i]) * z;
}
}
ans = (int)ans;
printf("%.0lf", ans);
return 0;
}
7-12 文件传输(25 分)
当两台计算机双向连通的时候,文件是可以在两台机器间传输的。给定一套计算机网络,请你判断任意两台指定的计算机之间能否传输文件?
输入格式:
首先在第一行给出网络中计算机的总数 N (2≤N≤104),于是我们假设这些计算机从 1 到 N 编号。随后每行输入按以下格式给出:
I c1 c2
其中I
表示在计算机c1
和c2
之间加入连线,使它们连通;或者是
C c1 c2
其中C
表示查询计算机c1
和c2
之间能否传输文件;又或者是
S
这里S
表示输入终止。
输出格式:
对每个C
开头的查询,如果c1
和c2
之间可以传输文件,就在一行中输出"yes",否则输出"no"。当读到终止符时,在一行中输出"The network is connected."如果网络中所有计算机之间都能传输文件;或者输出"There are k
components.",其中k
是网络中连通集的个数。
输入样例 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
输出样例 1:
no
no
yes
There are 2 components.
输入样例 2:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S
输出样例 2:
no
no
yes
yes
The network is connected.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
#define INF 100000000
typedef pair<int, int> P;
#define N 10001
const int mod = 10007;
int par[N];
int rak[N];
bool used[N];
int init()
{
for(int i = 0; i < N; i++)
par[i] = -1, rak[i] = 0;
}
int find(int x)
{
if(-1 == par[x])
return x;
else
return par[x] = find(par[x]);
}
void unite(int x, int y)
{
x = find(x);y = find(y);
if(x == y)
return;
if(rak[x] > rak[y])
par[y] = x;
else{
par[x] = y;
if(rak[x] == rak[y])
rak[y]++;
}
}
int main()
{
int n, a, b, cnt = 0;
set<int> s;
char c;
cin >> n;
init();
while(1){
cin >> c;
//printf("%d %d\n", find(a), find(b));
if(c == 'C'){
cin >> a >> b;
if(find(a) == find(b))
cout << "yes\n";
else
cout << "no\n";
}else if(c == 'I'){
cin >> a >> b;
unite(a, b);
}else{
break;
}
}
for(int i = 1; i <= n; i++){
int tmp = find(i);
if(tmp != i){
if(s.find(tmp) != s.end())
cnt++;
else{
s.insert(tmp);
cnt += 2;
}
}
}
if(cnt == n)
printf("The network is connected.\n");
else
printf("There are %d components.", s.size() + (n - cnt));
return 0;
}
7-13 公路村村通(30 分)
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。
输入样例:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
输出样例:
12
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
#define INF 100000000
typedef pair<int, int> P;
#define N 10000
const int mod = 10007;
struct Edge{
int u, v, w;
}edge[N];
int tol;
void add(int u, int v, int w)
{
edge[tol].u = u;
edge[tol].v = v;
edge[tol++].w = w;
}
bool cmp(Edge & a, Edge &b)
{
return a.w < b.w;
}
int par[N], rak[N];
void init(int n)
{
for(int i = 0; i < n; ++i){
par[i] = i;rak[i] = 0;
}
}
int find(int x)
{
if(x == par[x])
return x;
else
return par[x] = find(par[x]);
}
int unite(int x, int y)
{
x = find(x);y = find(y);
if(rak[x] > rak[y])
par[y] = x;
else{
par[x] = y;
if(rak[x] == rak[y])
rak[y]++;
}
}
int Kruskal(int n)
{
init(n);
sort(edge, edge + tol, cmp);
int cnt = 0;
int ans = 0;
for(int i = 0; i < tol; i++){
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
int t1 = find(u), t2 = find(v);
if(t1 != t2){
ans += w;
unite(t1, t2);
cnt++;
}
if(cnt == n - 1)
break;
}
return cnt < n - 1?-1:ans;
}
int main()
{
int n, m, u, v, w;
scanf("%d%d", &n, &m);
while(m--){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
printf("%d\n", Kruskal(n));
return 0;
}