題目
https://www.patest.cn/contests/pat-a-practise/1034
題意:給出1000條以內的通話記錄A B和權值w,如果一個團伙人數超過2人並且通話總權值超過閾值k,令團伙裏面的自身權值的最大值爲頭目,輸出所有滿足條件的團伙的頭目,和他們團伙裏面的人數。
解題思路
數據結構
鄰接表存放圖的鄰接關係,weight數組存放節點權重
- 鄰接節點 = 它通話過的所有節點
- 每個節點的權重 = 它所在的通話記錄時間之和
用
map<string, int>
和vector<string>
形成雙射,爲字符串分配整數值,同時將整數值對應到字符串。
算法
用BFS實現對圖的遍歷,注意到可能有多個連通分量,因此涉及到調用多次BFS。
在BFS中,每次出隊就累加團隊人數、累加團隊總權重、更新該團隊裏的最大權重,然後將該節點的鄰接節點入隊(注意一定是未訪問過的)。
需要注意的是,輸入的路徑數N最大值爲1000,所以最多可能要2000個節點!(否則會出現測試點4的段錯誤)
AC代碼
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 2005; //路徑數爲1000,但節點數可能爲2000!
map<string, int> getStrIndex; //字符串對應的索引
string s[maxn]; //s[1..cnt]存放索引對應的字符串
map<string, int> ans; //存放輸出結果,自動排序
int cnt = 0;
vector<int> adj[maxn]; //鄰接表
int weight[maxn]; //每個節點的權重
bool visited[maxn]; //標記每個節點是否訪問過
void BFS(int start, int &head, int &member, int &sum)
{
queue<int> q;
q.push(start);
visited[start] = true;
int out, son;
int cur_max = 0; //最大值
while (!q.empty())
{
out = q.front(); q.pop(); //隊首出隊
member++; //羣人數累加
sum += weight[out]; //羣總權重累加
if (weight[out] > cur_max) //更新最大權重
{
cur_max = weight[out];
head = out;
}
for (int i = 0; i < adj[out].size(); ++i) //鄰接節點入隊
{
son = adj[out][i];
if (!visited[son]) //必須是未訪問過的
{
q.push(son);
visited[son] = true;
}
}
}
}
void init(int n) //初始化全局變量
{
for (int i = 0; i < maxn; ++i)
{
weight[i] = 0;
visited[i] = false;
adj[i].clear();
}
}
int alloc_index(const string &x) //獲得字符串s的索引
{
if (getStrIndex[x] == 0) //新的字符串
{
getStrIndex[x] = ++cnt;
s[cnt] = x;
}
return getStrIndex[x]; //返回索引值
}
void solve(int n, int threshold)
{
init(n);
string a, b;
int w;
for (int i = 0; i < n; ++i) //輸入
{
cin >> a >> b >> w;
int idxa = alloc_index(a), idxb = alloc_index(b);
weight[idxa] += w;
weight[idxb] += w;
adj[idxa].push_back(idxb); //標記鄰接
adj[idxb].push_back(idxa);
}
for (int i = 1; i <= cnt; ++i)
{
if (!visited[i]) //出現新的連通集
{
int head = 0, member = 0, sum = 0;
BFS(i, head, member, sum); //傳參調用BFS
if (member > 2 && (sum>>1) > threshold) //羣人數大於2且羣權重大於閾值
ans[s[head]] = member;
}
}
cout << ans.size() << endl; //map自動排序
for (auto it = ans.begin(); it != ans.end(); ++it)
cout << it->first << ' ' << it->second << endl;
}
int main()
{
ios::sync_with_stdio(false);
int n, k;
cin >> n >> k;
solve(n, k);
}