思路
- 用hash的方法来映射每个人的名字,用邻接表存储节点
- 每个点权在DFS中一次循环中相加
ans+=adj[u][i].weight;从而超出头目。
- 总边权把一个连通图的所有边相加除以二,因为重复计算了一次
weight_total+=adj[u][i].weight
最后对名字进行字典序排序就完事了
注意
- 学会结构体初始化函数。
node(int _weight,int _v) :weight(_weight),v(_v) {}!!!!!
- 熟练使用map和string会简单很多,和节省很多空间,代码二为使用map做法。!!!!!!
- 十进制与其他进制的转换。!!!!!!
- 数组不能直接做返回值,除非使用了new赋予了空间来返回指针 !!!!!!!!
- 边权和点权的统计要在dfs递归之前,因为不考虑重复和环,否则要删除掉以访问的边,具体见代码二。
- 可以建立两个map对名字和编号分别映射,见代码二。
- map可以直接排序,非常简单。
代码一
#include<vector>
#include<algorithm>
using namespace std;
int person,weight_total;
const int maxn=101000; //要稍微大一点,映射完全部字符
int N,K;
int vis[maxn]={0}; //标记数组
int max_weight,max_v; //头目的权值和标号
struct node{ //节点
int weight;
int v;
node(int _weight,int _v) :weight(_weight),v(_v) {
}
};
struct gang{ //帮派
char head[4]; //头目名
int person; //人数
}gangs[maxn];
vector<node> adj[maxn];
bool cmp(gang a,gang b){ //比较头目的字典序
if(a.head[0]!=b.head[0]) return a.head[0]<b.head[0];
else if(a.head[1]!=b.head[1]) return a.head[1]<b.head[1];
else return a.head[2]<b.head[2];
}
int judge(int a,int b){ //判断是否有边,有返回在边表的位置
for(int i=0;i<adj[a].size();i++){
if(adj[a][i].v==b) return i;
}
return -1;
}
int trans(char a[]){ //名字映射为对应的哈希值
int temp=0;
for(int i=0;i<3;i++){
temp=temp*26+a[i]-'A';
}
return temp;
}
void trans2(int n,char temp[]){ //哈希值映射回名字
temp[0]=n/26/26+'A';
temp[1]=n%(26*26)/26+'A';
temp[2]=n%26+'A';
temp[3]='\0';
}
void DFS(int u){
vis[u]=0;
person++;
int ans=0;
for(int i=0;i<adj[u].size();i++){
int v=adj[u][i].v;
ans+=adj[u][i].weight; //统计点权
weight_total+=adj[u][i].weight; //统计总边权
if(vis[v]==1){
DFS(v);
}
}
if(ans>max_weight){ //找首领
max_v=u;
max_weight=ans;
}
}
int main(){
scanf("%d%d",&N,&K);
char v1[4],v2[4];
int w;
for(int i=0;i<N;i++){ //建立图
scanf("%s %s %d",v1,v2,&w);
int x1=trans(v1);
int x2=trans(v2);
adj[x1].push_back(node(w,x2));
adj[x2].push_back(node(w,x1));
vis[x1]=vis[x2]=1; //标记为x1,x2存在于图中
}
int up_limit=26*26*26;
int count=0;
for(int i=0;i<=up_limit;i++){
if(vis[i]==1){
max_v=max_weight=weight_total=person=0; //分别是周围边权值最大定点和对应权值,帮派的总权值和人数
DFS(i);
if(weight_total/2>K&&person>2){ //所有边重复计算了一次,因此除以2
trans2(max_v,gangs[count].head);
gangs[count++].person=person;
}
}
}
printf("%d\n",count);
sort(gangs,gangs+count,cmp); //排序
for(int i=0;i<count;i++){
printf("%s %d\n",gangs[i].head,gangs[i].person);
}
return 0;
}
代码二
#include<map>
#include<string>
#include<iostream>
const int maxn=2010;
using namespace std;
map<int,string> intTostring; //名字到编号
map<string,int> stringToint; //编号到名字
map<string,int> gangs; //名字
int G[maxn][maxn];
int weight[maxn]; //点权
int n,k,numPerson=0;
bool vis[maxn]={false};
int change(string str){
if(stringToint.find(str)!=stringToint.end()){
return stringToint[str];
}
else {
stringToint[str]=numPerson;
intTostring[numPerson]=str;
return numPerson++;
}
}
void DFS(int u,int &head,int &numMember,int &totalValue){
vis[u]=true;
numMember++;
if(weight[u]>weight[head]) head=u;
for(int i=0;i<numPerson;i++){
if(G[u][i]>0){
totalValue+=G[u][i];
G[u][i]=G[i][u]=0;
if(vis[i]==false){
DFS(i,head,numMember,totalValue);
}
}
}
}
void DFSTrave(){
for(int i=0;i<numPerson;i++){
if(vis[i]==false){
int head=i,numMember=0,totalValue=0;
DFS(i,head,numMember,totalValue);
if(numMember>2&&totalValue>k){
gangs[intTostring[head]]=numMember;
}
}
}
}
int main(){
cin>>n>>k;
int w;
string str1,str2;
for(int i=0;i<n;i++){
cin>>str1>>str2>>w;
int x1=change(str1);
int x2=change(str2);
weight[x1]+=w;
weight[x2]+=w;
G[x1][x2]+=w;
G[x2][x1]+=w;
}
DFSTrave();
cout<<gangs.size()<<endl;
map<string,int>::iterator it;
for(it=gangs.begin();it!=gangs.end();it++){
cout<<it->first<<" "<<it->second<<endl;
}
return 0;
}