1.题目的大意是给出很多人(结点)之间的通话记录,每两人之间的权重取决于他俩通话权重的总时长,如果一个社区的人数超过2且社区内发生的通话总时长超过给定阈值,那么这属于一个社区。最后要求输出社区的总数,再按照社区头目的姓名字母序从小到大输出头目姓名和社区人数。

2. DFS的注意点,这是我第一次写图的DFS。根据教材给的总结出需要两个函数:DFS(int no,int socNo)DFStraver(),由后者调用前者,至于参数是根据实际情况决定的。配套还要有一个布尔数组vis[maxn]来记录每一个点是否被访问过。

3.vis[maxn]的修改发生在DFS(int no,int socNo)内部,第一句话就是。被用到是在DFStraver()的进入搜索之前。一般来说在DFS(int no,int socNo)的内部,开始遍历当前节点的所有邻接结点时,一是要判断是不是邻接结点,而是要判断该邻接节点是否被访问过。但是本题我起初这么做的时候,发现第三个社区就没有被当作社区,输出权重才发现该社区的总权重被算出是50。如图所示

why?一定是FFF和HHH之间的那条边没算进权重,究其原因,该社区的进入结点是FFF,第二个是GGG,第三个是HHH,但是当HHH开始遍历其子节点的时候,会发现唯一的子节点FFF(GGG和HHH之间的边已经被擦除)被访问过了。所以FFF和HHH之间那条边自然也就不会但算进去。怎么解决呢?自然是要把遍历子节点前判断是否已经访问过的条件给删掉。

void DFS(int no,int socNo){//传入人的编号和社区编号 vis[no] = true;//处理社区头目问题 int headNo = social[socNo].head;if(wper[no]>wper[headNo])social[socNo].head = no;//处理社区人数问题social[socNo].pers.insert(no);for(int i=0;i<totalNum;i++){if(adj[no][i]!=0){//处理社区权重问题social[socNo].totalWei += adj[no][i];//擦掉加入过的这条边adj[no][i] = adj[i][no] = 0; DFS(i,socNo);}}
}void DFStraver(){for(int i=0;i<totalNum;i++){if(vis[i]==false){DFS(i,socNum);if(social[socNum].pers.size()>2&&social[socNum].totalWei>thre)validNum++;socNum++;}}
}

4.  但是当我删掉,新的问题来了,这样FFF这个结点会被算作两次,导致社区三的节点总数被记作了4。于是我想到集合的去重功能,不再在社区结构体设置人数这一变量,而是设置set<int>来记录编号,调用size()函数得到人数。

struct Social{int head = maxn;//社区的头头set<int> pers;//人的编号 int totalWei = 0;//总权重
}social[maxn];

5. 在记入一条边的权重后,记得将这条边删除(我也是看参考书才知道),但是注意了这是无向图,邻接矩阵中的两个相互对称的位置都记录了这条边,所以抹零两个数。

6. 下面的三剑客是方便将string和int互相映射,不是哈希那种哦,注意学习

map<string,int> strToIntMp;//姓名从字符串映射到编号map<int,string> intToStrMp;//姓名从编号映射到字符串int archive(string s){if(strToIntMp.find(s)!=strToIntMp.end())return strToIntMp[s];//说明这个人已经存档过了//如果没有,要先确定他是第几号 int num = strToIntMp.size();//两个映射集是同步的 strToIntMp[s] = num;intToStrMp[num] = s;return num;
} 

7. 急性子与慢性子

最后唠叨一点细枝末节。可以让代码结构更清晰。

急性子:由于是每个社区权重最大的那个人做头头,所以开了一个int数组,存放每个人的权重,这个和邻接矩阵一样,一边读入一边就该加上了。

int wper[maxn] = {0};//每个人的权重
for(int i=0;i<n;i++){cin>>p1>>p2>>ct;no1 = archive(p1);no2 = archive(p2);wper[no1] += ct;wper[no2] += ct;adj[no1][no2] += ct; adj[no2][no1] += ct;
}

慢性子:我一开始没注意到要输出真正的社区(达到了那两条要求)的个数,想着设置一个统计总的社区个数的全局变量socNum就好了,最后排好序再把不合格的给过滤掉。但是亡羊补牢也为时未晚,再设置一个统计真正的社区数的全局变量validNum,这个也在DFStraver()中,每次结束一个新社区的遍历后更新。可以见得,过滤放最后也没关系。

void DFStraver(){for(int i=0;i<totalNum;i++){if(vis[i]==false){DFS(i,socNum);if(social[socNum].pers.size()>2&&social[socNum].totalWei>thre)validNum++;socNum++;}}
}

AC代码

#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<cstring>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<cmath>
typedef long long LL;using namespace std;const int maxn = 2010;int wper[maxn] = {0};//每个人的权重bool vis[maxn] = {false};//是否被遍历到 int adj[maxn][maxn] = {0};//邻接矩阵(本题是无向图) map<string,int> strToIntMp;//姓名从字符串映射到编号map<int,string> intToStrMp;//姓名从编号映射到字符串int archive(string s){if(strToIntMp.find(s)!=strToIntMp.end())return strToIntMp[s];//说明这个人已经存档过了//如果没有,要先确定他是第几号 int num = strToIntMp.size();//两个映射集是同步的 strToIntMp[s] = num;intToStrMp[num] = s;return num;
} int n,thre;//call-num,threshold
int totalNum;//总人数 struct Social{int head = maxn;//社区的头头set<int> pers;//人的编号 int totalWei = 0;//总权重
}social[maxn];int socNum = 0;//社区个数
int validNum = 0;//有效社区数 void DFS(int no,int socNo){//传入人的编号和社区编号 vis[no] = true;//处理社区头目问题 int headNo = social[socNo].head;if(wper[no]>wper[headNo])social[socNo].head = no;//处理社区人数问题social[socNo].pers.insert(no);for(int i=0;i<totalNum;i++){if(adj[no][i]!=0){//处理社区权重问题social[socNo].totalWei += adj[no][i];//擦掉加入过的这条边adj[no][i] = adj[i][no] = 0; DFS(i,socNo);}}
}void DFStraver(){for(int i=0;i<totalNum;i++){if(vis[i]==false){DFS(i,socNum);if(social[socNum].pers.size()>2&&social[socNum].totalWei>thre)validNum++;socNum++;}}
}bool cmp(Social a,Social b){return intToStrMp[a.head]<intToStrMp[b.head];
} int main(){scanf("%d %d",&n,&thre);string p1,p2;//person1 person2int no1,no2;//上面两个人的编号 int ct;//call timefor(int i=0;i<n;i++){cin>>p1>>p2>>ct;no1 = archive(p1);no2 = archive(p2);wper[no1] += ct;wper[no2] += ct;adj[no1][no2] += ct; adj[no2][no1] += ct;}//进行深度优先搜索totalNum = strToIntMp.size();//总人数DFStraver();sort(social,social+socNum,cmp);//按照头头的姓名字母序从小到大排序 //输出有效社区总数 printf("%d\n",validNum);for(int i=0;i<socNum;i++){if(social[i].pers.size()>2&&social[i].totalWei>thre){cout<<intToStrMp[social[i].head];printf(" %d\n",social[i].pers.size());} } return 0;
}

1034 Head of a Gang(图的DFS解法) 擦边大法好相关推荐

  1. 1013 Battle Over Cities(图的DFS解法)

    这题的背景是战争年代,假如城市1被占领,那么所有和城市1相关的公路都要被炸毁,但是这样一来,2和3就不连通了,所以需要补修一条23之间的公路.但是换做城市2或3被占领,1和另一座城市是联通的,并不需要 ...

  2. PAT:1034 Head of a Gang (30分)

    1034 Head of a Gang (30分) One way that the police finds the head of a gang is to check people's phon ...

  3. pat 甲级 1034. Head of a Gang (30)

    1034. Head of a Gang (30) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue One wa ...

  4. 图:DFS(深度优先搜索)图解分析代码实现

    文章目录 一.简介 二.图的建立 2.1建立图类 2.2建立图 三.DFS 3.1图解 3.2代码 一.简介 图的DFS(深度优先搜索)与BFS(广度优先搜索)是图的两种遍历方式. 主要区别在于当到达 ...

  5. leetcode 433. Minimum Genetic Mutation | 433. 最小基因变化(图的DFS)

    题目 https://leetcode.com/problems/minimum-genetic-mutation/ 题解 图的 DFS,思路见草稿: class Solution {int N;pu ...

  6. LeetCode 200. Number of Islands--c++ dfs解法

    LeetCode 200. Number of Islands LeetCode题解专栏:LeetCode题解 LeetCode 所有题目总结:LeetCode 所有题目总结 大部分题目C++,Pyt ...

  7. (最优解法)46行代码AC_HDU1242 Rescue(DFS解法+BFS解法)

    励志用少的代码做高效表达 Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. T ...

  8. 第十二周项目五-----迷宫问题之图深度优先遍历解法

     烟台大学计算机与控制工程学院 作者:孙潇 时间:2015年12月15日 问题描述:[项目 - 迷宫问题之图深度优先遍历解法]   设计一个程序,采用深度优先遍历算法的思路,解决迷宫问题.   ( ...

  9. 鱼刺图战略分解法在绩效管理中的应用

    鱼刺图战略分解法在绩效管理中的应用 一.概述 鱼刺图是由日本管理大师石川馨先生所发展出来的,故又名石川图,如图1所示.鱼刺图战略分解法就是在企业绩效管理方案设计过程中应用鱼刺图工具进行企业战略目标分解 ...

最新文章

  1. 关于嵌入式开发,到底需要会多少门语言,做好准备了吗
  2. openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 四
  3. perf +火焰图使用
  4. html 拖拽选择表格,JS拖动选择table里的单元格完整实例【基于jQuery】
  5. java未发现数据源名称并且未指定默认驱动程序_转:java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序...
  6. 安全攻防六:SQL注入,明明设置了强密码,为什么还会被别人登录
  7. 网页右下角弹出的图片无法显示
  8. Python学习笔记--解析式
  9. linux系统查看dns缓存,如何清空linux的DNS缓存
  10. 公司企业如何设计微信小程序?
  11. 异常:Incorrect result size: expected 1, actual 0
  12. python数据分析-pandas学习
  13. office2003 安装步骤及注意事项
  14. 计算机组成原理:真值,原码,补码,反码,移码
  15. element日历上月下月样式修改
  16. 我看《肖申克的救赎》
  17. WinForm小心AutoSize属性!
  18. 李宏毅深度学习(一)
  19. Internet History, Technology, and Security(week1)——History: Dawn of Electronic Computing
  20. 天龙八部是很有味道的小说

热门文章

  1. Swift 条件编译,编译标记
  2. UIView Animation
  3. LeetCode-135-Candy
  4. PHP协程:并发 shell_exec
  5. Windows 日志高级筛选实践
  6. 如何查看Linq to SQL运行时,实际执行的Sql语句
  7. 网络配置文件、命令详解
  8. postfix邮件服务器搭建
  9. BGP相邻体之间磋商的过程
  10. 大闸蟹的OO第二单元总结