PAT1034 Head of a Gang

49 篇文章 0 订阅

上次三月没满分。。开始准备搞九月了,希望这次能满分吧。3月份的时候英文太差了,看的好累,现在感觉还好了些,看运气了。(其实目前唯一自信的科目只有数学,别的。。都是随缘佛系)。

今天做了这道题。。我就服了,我三月去的时候没做这道,结果三月是题设背景和这题基本一样的题目就是加深复杂了一点。。我当时都看不懂Gang是什么意思。。血崩。

应该是要并查集做,我这边锻炼下模拟能力用STL模拟做了一下也过了,下面是题解(保佑我九月PAT满分。。初试高分(英语过线就好了!!!!))。

One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A "Gang" is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threthold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads.

Input Specification:

Each input file contains one test case. For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threthold, respectively. Then N lines follow, each in the following format:

Name1 Name2 Time

where Name1 and Name2 are the names of people at the two ends of the call, and Time is the length of the call. A name is a string of three capital letters chosen from A-Z. A time length is a positive integer which is no more than 1000 minutes.

Output Specification:

For each test case, first print in a line the total number of gangs. Then for each gang, print in a line the name of the head and the total number of the members. It is guaranteed that the head is unique for each gang. The output must be sorted according to the alphabetical order of the names of the heads.

Sample Input 1:

8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10

Sample Output 1:

2
AAA 3
GGG 3

Sample Input 2:

8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10

Sample Output 2:

0

题目意思:给一堆通话记录,从这些通话记录里面我们可以推断知道哪些人是一伙的,判断是不是形成了一个团伙,也就是小团队里面互有联系,而且通话时间总和超过给定值,同时人数要大于2....如果形成了团伙,同时找出头目。就是团伙中通话时间最长的那个,然后输出一下,保证头目只有一个,按头目的字母序输出一下即可。

思路:理论上要并查集的。但是心血来潮模拟了一下,还是给模拟出来了。占空间会很大。有种OOP的思想在里面。

就是先建立同伙结构体:成员,是否有效的标志,总的那个通话时间,头目(后来发现并不用,可以删掉).

然后是两个map,key均为string即成员姓名,恩,很简单了。其中一个map指向gflag,为所属团伙的下标+1,如果没有团伙归属那就是0,然后另一个map指向总时间,表示这个人总的通话时间。

后面的思路就simple了哈哈,用一个vector存放gangs,每次读入一条通话记录的时候,只要检查这两个人的名字所指向的gflag情况就行了,分以下几种情况:

1.两个人都没有归属的团伙,也就是两个gflag都是0:

这个时候很显然的就是要new 一个团伙出来,然后把成员加进去,标志初始化为0,0表示有效,通话时间对应改成的当前读进来的时间。然后将这个gang加进数组,把对应的这两个人对应的gflag初始化成这个刚进去的gang的下标,也就是当前数组的尺寸.

上面几步操作,顺序无所谓。

2.两个人有一个已经有团伙了,另一个还没有。

这个比上面还要简单,直接把没有的那个加到有的那个里面去,时间和成员更新一下就完事了。

3.两个人都有团伙了,且是同一个。

这个很明显了,直接把时间加上就ok。

4.两个人都有团伙了,但不是同一个。

这个略微复杂,但也不是很难,显而易见的就是把其中一个合并过去。为了时间考虑我们选择把人数少的合到人数多的地方去,然后我们考虑怎么合,第一步肯定是小团伙的成员遍历一遍并且加到另一个团伙那边去,在这同时我们要把这里小团伙成员的gflag都指向那个大团伙不就搞定了?但是不要忘记时间!!对应的要把小团伙的总时间加过去的同时还要把这条记录的时间加过去!!

也许你会问,那我那个小团伙怎么办erase吗,首先,肯定不能erase,因为你一erase,你的那些gflag全乱了啊,肯定不行的,那怎么办,这就是我为什么设置个团伙有效的标志了,直接小团伙有效标志置为1,无效,然后遍历的时候不是0的全部不看就是了。

这样就读入完数据了,剩下就是一些正常的处理这里就不讲了,没什么好讲,下面是代码。

当然,肯定是并查集方便,这只是读书之余的一种休闲。

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<iomanip>
#include<time.h>
#include<math.h>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string.h>
using namespace std;
struct gang {
	set<string> mem;//成员
	int time;//通话总时间
	string head;//头目,弃用
	int de;//有效标志,0有效,1无效
};
struct resu {
	string headd;//头目名字
	int mems;//团伙人数
};
map<string, int> gflag;//纪录当前人所属的团伙标号=下标+1
map<string, int> ptime;//记录当前人总的通话时间,便于后面比较
vector<gang> gangs;//团伙
void merge(int a,int b,int t){
	for (auto i = gangs[b].mem.begin(); i != gangs[b].mem.end(); i++) {
		gflag[*i] = a+1;
		gangs[a].mem.insert(*i);
	}
	gangs[a].time += gangs[b].time;
	gangs[a].time += t;
	gangs[b].de = 1;
}
bool sss(resu a, resu b) {
	return a.headd < b.headd;
}
int main()
{
	int n, m;
	scanf("%d %d", &n,&m);
	for (int i = 0; i < n; i++) {
		string a, b; int t;
		cin >> a >> b >> t;
		ptime[a] += t;
		ptime[b] += t;
		if (gflag[a] == 0 && gflag[b] == 0) {
			gang tmp;
			tmp.time = 0;
			tmp.time += t;
			tmp.mem.insert(a);
			tmp.mem.insert(b);
			tmp.de = 0;
			gflag[a] = gangs.size()+1;
			gflag[b] = gangs.size() + 1;
			gangs.push_back(tmp);
		}
		else if (gflag[a] == 0 && gflag[b] != 0) {
			gangs[gflag[b] - 1].time += t;
			gangs[gflag[b] - 1].mem.insert(a);
			gflag[a] = gflag[b];
		}
		else if (gflag[a] != 0 && gflag[b] == 0) {
			gangs[gflag[a] - 1].time += t;
			gangs[gflag[a] - 1].mem.insert(b);
			gflag[b] = gflag[a];
		}
		else {
			if (gflag[a] == gflag[b]) {
				gangs[gflag[a] - 1].time += t;
			}
			else {
				int a1, b1;
				if (gangs[gflag[a] - 1].mem >= gangs[gflag[b] - 1].mem) {
					a1 = gflag[a] - 1;
					b1 = gflag[b] - 1;
				}
				else {
					a1 = gflag[b] - 1;
					b1 = gflag[a] - 1;
				}
				merge(a1, b1,t);
			}
		}
	}
	vector<resu> res;
	for (int i = 0; i < gangs.size(); i++) {
		if (gangs[i].de == 0 && gangs[i].time > m&&gangs[i].mem.size()>2) {
			string hee;
			int max = 0;
			for (auto j = gangs[i].mem.begin(); j != gangs[i].mem.end(); j++) {
				if (ptime[*j] > max) {
					max = ptime[*j];
					hee = *j;
				}
			}
			resu ttt;
			ttt.headd = hee;
			ttt.mems = gangs[i].mem.size();
			res.push_back(ttt);
		}
	}
	printf("%d\n", res.size());
	sort(res.begin(), res.end(), sss);
	for (int i = 0; i < res.size(); i++) {
		cout << res[i].headd << " " << res[i].mems << endl;
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值