1034 Head of a Gang(30分)

题目翻译:

给定N条通话记录和一个限制K。每条通话记录包含了两个名字和一个通话时间,相互联系的人同属于一个帮派。题目要求,只有人数超过2人并且总通话时长超过K的集体才能算作帮派Gang,并且帮派内部通话时长最长的人是帮派首领Boss。

题解思路:

  1. 通过两个map,来完成name和id的互相映射,方便哈希查找。
  2. 再用一个map,来保存头领姓名和帮派人数的,保存答案。
  3. w[]数组来保存每个人的通话时间,g[][]来保存边的权重,并且方便dfs找到帮派
  4. 找到新的w更大的结点,head指向该结点,成为新的头领。
  5. totalweight来记录每个帮派的总通话时间。一定要记住,先遍历边,累加了通话时间,之后一定要把这条边删除。这样一方面避免出现环的情况,造成边权重漏加或者重复加的情况。

代码:

并查集:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 100;
const int M = N * 10 ;
const int mod = 1e9 + 7;
const double eps = 1e-9;
typedef pair<int, int> PII;
#define endl '\n'
#define x first
#define y second
#define INF 0x3f3f3f3f
#define ls(k) k << 1
#define rs(k) k << 1 | 1
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
int n, m, total;
unordered_map<string, int> num;
unordered_map<int, string> name;
map<string, int> ans;
vector<int> gang[N];
int p[N], w[N], k[N];

void create(string x)
{
    if(!num[x])
    {
        num[x] = ++ total;
        name[total] = x;
    }
}

int find(int x)
{
    return p[x] == x ? x : p[x] = find(p[x]);
}

void merge(int a, int b, int t)
{
    int fa = find(a), fb = find(b);
    if(fa == fb)
    {
       k[fa] += t;
       return;
    }

    p[fa] = fb;
    k[fb] += k[fa] + t;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    cin >> n >> m;

    for (int i = 1; i <= n; i ++) p[i] = i;

    for(int i = 1; i <= n; i ++)
    {
        string a, b;
        int t;
        cin >> a >> b >> t;
        create(a), create(b);
        w[num[a]] += t;
        w[num[b]] += t;
        merge(num[a], num[b], t);
    }

    for (int i = 1; i <= total; i ++) gang[find(i)].push_back(i);

    for (int i = 1; i <= total; i ++)
    {
        if(k[i] <= m || gang[i].size() <= 2) continue;

        int head = i;
        for (auto j : gang[i])
        {
            if(w[j] > w[head]) head = j;
        }
        ans[name[head]] = gang[i].size();

    }
    cout << ans.size() << endl;
    for (auto i : ans) cout << i.first << " " << i.second << endl;

    return 0;
}

DFS(柳神):

#include <bits/stdc++.h>
using namespace std;
 
const int maxn=2010;
const int inf=1e8;
 
map<string,int> nameToid;//姓名转编号
map<int,string> idToname;//编号转姓名
map<string,int> gang;    //头领->人数
int n,k,number=0;        //通话记录数量,最低时间,总人数
int w[maxn]={0},G[maxn][maxn]={0};
bool vis[maxn]={false};
 
//遍历节点
void DFS(int now,int &head,int &gangnum,int &totalweight){
    gangnum++;     //成员数量增加
    vis[now]=true; //已经访问过当前结点
    if(w[now]>w[head]){
        head=now;    //找到权重最大的点,成为新的首领
    }
    for(int i=0;i<number;++i){
        if(G[now][i]>0){
            totalweight+=G[now][i];  //累加这条边
            G[now][i]=G[i][now]=0;   //将这两个点之间的边删除
            if(!vis[i]){ //如果下一个点还没被访问过,就访问
                DFS(i,head,gangnum,totalweight);
            }
        }
    }
}
 
//遍历整个图
void DFSTrave(){
    for(int i=0;i<number;++i){
        if(!vis[i]){
            int head=i,gangnum=0,totalweight=0; //不要忘了初始化
            DFS(i,head,gangnum,totalweight);
            if(gangnum>2 && totalweight>k){
                    //gang是保存name对应人数的
                gang[idToname[head]]=gangnum;
            }
        }
    }
}
//完成名字和id的编号,方便查找
int change(string s){
    //找到的话,就不需要再添加姓名了
    if(nameToid.find(s)!=nameToid.end()){
        return nameToid[s];
    }else{
        nameToid[s]=number;
        idToname[number]=s;
        return number++;
    }
}
int main(){
    int weight;
    cin >> n>>k;
    string s1,s2;
    for(int i=0;i<n;++i){
        cin >> s1>>s2 >>weight;
        int id1=change(s1);
        int id2=change(s2);
        w[id1]+=weight;         //保存到对应的权重里
        w[id2]+=weight;
        G[id1][id2]+=weight;    //保存到邻接矩阵里面
        G[id2][id1]+=weight;
    }
    DFSTrave();
    cout << gang.size()<<"\n";
    //因为map是按照关键字从小到大输出的,所以不用排序
    map<string,int>::iterator it;
    for(it=gang.begin();it!=gang.end();++it){
        cout << it->first << " "<< it->second<<"\n";
    }
    return 0;
}

再贴一个看错题(以为姓名只能是AAA这种都一样的形式,最后导致只能过两个点)

 

#include<bits/stdc++.h>
using namespace std;
map<char, int> p;
map<int, int> c;
int N, K;
int f[1010];

int find(int x)
{
	if (x != f[x]) f[x] = find(f[x]);
	return f[x];
}

struct node {
	int num = 0, sum = 0, index = -1;
};
vector<node> m(26);

bool comp(node n1, node n2)
{
	return n1.index < n2.index;
}

int main()
{
	cin >> N >> K;
	for (int i = 0;i < 26;i++)
		p['A' + i] = i;
	for (int i = 0;i < 1010;i++)
		f[i] = i;
	for (int i = 0;i < N;i++)
	{
		string a, b;
		int temp;
		cin >> a >> b >> temp;
		c[p[a[0]]] += temp;
		c[p[b[0]]] += temp;
		int x = find(p[a[0]]), y = find(p[b[0]]);
		if (x != y) f[y] = x;
	}
	int cnt = 0;//集合个数
	for (int i = 0;i < m.size();i++)
	{
		m[find(i)].num++;
		m[find(i)].sum += c[i];
		if (m[find(i)].index == -1 || c[i] > c[m[find(i)].index])
			m[find(i)].index = i;
	}
	sort(m.begin(), m.end(), comp);
	for (int i = 0;i < 26;i++)
	{
		if (m[i].num >= 3 && m[i].sum > K*2)
			cnt++;
	}
	cout << cnt << endl; 
	for (int i = 0;i < 26;i++)
	{
		if(m[i].num >= 3 && m[i].sum > K*2)
			cout << char(m[i].index + 'A') << char(m[i].index + 'A') << char(m[i].index + 'A') << " " << m[i].num << endl;
	}
}

坑点:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值