1. 程式人生 > 其它 >PTA 1034 Head of a Gang (30 分)

PTA 1034 Head of a Gang (30 分)

考察知識點:並查集

我使用的資料結構:map、vector

可能的坑點:

1.本來以為每個人的名字是由相同的A-Z之間字母組成(too young too simple T T),然後我沒想到用map記錄每個名字出現的情況,好的這一次提交就4分

2.知道名字是三個大寫英文字母的隨機組合,那我不得不用map記錄了,然後為了後續好按照名字排序(這也是我沒審清題錯了好久的點),這一次就14分吧好像

3.記得map中存放的是(名字,對應資訊所存放的結構體下標),敲程式碼的時候注意不能弄亂了

4.電話時間看輸入像有向邊,其實是無向邊,所以我在結構體中設定了weight,用於儲存該人的總通話數,記得輸入時,要把這個通話時間給雙方加上

5.求每個叢集老大下標時,要注意每個叢集人數>2, 該叢集通話時間(就是這個叢集所有人電話時間總和/2)>閥值

6.我直接用vector<Person>存每個叢集老大的結構體,方便後續按名字排序。

 

感嘆PTA無論甲、乙都好細節,確實考驗我的耐心...遇到這種30分的題,可能要磕上2小時,才能把細節理清楚,好菜呀嗚嗚

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include
<map> using namespace std; int fa[2010]; struct Person{ string name; int weight; int groupNum; }person[2010]; //這記得設定成1000*2以上,因為最差的情況每次打電話的雙方都是之前沒出現過的使用者 map<string,int> myMap; void inital(int n){ //初始化集合 for(int i=0;i<n;i++){ fa[i]=i; } } int Find(int rt){ //找到祖宗 return
fa[rt]==rt?rt:Find(fa[rt]); } void Union(int r1,int r2){ //集合合併 int f1=Find(r1); int f2=Find(r2); if(f1!=f2){ fa[f2]=f1; } } bool cmp(Person p1,Person p2){ //按名字字母順序排序 return p1.name<p2.name; } int main(void){ int n,k,index=0; scanf("%d %d",&n,&k); inital(2*n); for(int i=0;i<n;i++){ string n1,n2; int call; cin>>n1>>n2>>call; if(myMap.count(n1)==0){ //若該使用者之前還沒出現過就新增進來 person[index].name=n1; person[index].weight+=call; myMap[n1]=index++; } //若該使用者出現過,則只用加上其打電話的時間 else{ person[myMap[n1]].weight+=call; } if(myMap.count(n2)==0){ person[index].name=n2; person[index].weight+=call; myMap[n2]=index++; } else{ person[myMap[n2]].weight+=call; } //合併兩個使用者集合 Union(myMap[n1],myMap[n2]); } vector<int> head; //這裡面存放的是每個叢集其中一個人的下標 vector<Person> real_head; //存放每個叢集老大的資訊 // vector<int> group; //找出有幾個叢集 for(int i=0;i<index;i++){ if(fa[i]==i){ head.push_back(i); //存入預備老大的集合 } } for(int i=0;i<head.size();i++){ int h=head[i]; //可能的叢集老大 int weight_sum=person[h].weight; //記錄最大時間 、 最大時間對應下標、叢集人數 int maxx_weight=weight_sum,maxx_index=h,group_num=0; for(int j=0;j<index;j++){ //若該使用者屬於該集合且不是當前可能的老大 if(Find(j)==h&&j!=h){ group_num++; weight_sum+=person[j].weight; //若當前這個人的總電話數最大,則記錄下來,這個過程就是找這個叢集老大 if(maxx_weight<person[j].weight){ maxx_weight=person[j].weight; maxx_index=j; } } } //若總電話時間(這裡除2是因為前面我把之前每對通話記錄當作無向邊把權重都加上到這個使用者的通話時間內,所以/2代表實際該叢集總電話數)大於閥值 if((weight_sum/2)>k&&(group_num+1)>2){ person[maxx_index].groupNum=group_num+1; real_head.push_back(person[maxx_index]); } } //對每個叢集老大按名字排序 sort(real_head.begin(),real_head.end(),cmp); printf("%d\n",real_head.size()); for(int i=0;i<real_head.size();i++){ cout<<real_head[i].name<<" "<<real_head[i].groupNum<<endl; } // cout<<count<<endl; return 0; }