1.学习总结
1.1图的思维导图
![博客作业06--图_第1张图片](http://img.e-com-net.com/image/info8/3ac12f557b964f1783d8923a874391ec.jpg)
![博客作业06--图_第2张图片](http://img.e-com-net.com/image/info8/b07a45471357434b8301c054eca45bdf.jpg)
![博客作业06--图_第3张图片](http://img.e-com-net.com/image/info8/6c32d1422da3438ebfd32a5b0c783447.jpg)
![博客作业06--图_第4张图片](http://img.e-com-net.com/image/info8/870ab24dcb4c477999282396d3071521.jpg)
![博客作业06--图_第5张图片](http://img.e-com-net.com/image/info8/a641a72167b447049af08ad05f5ff2ae.jpg)
![博客作业06--图_第6张图片](http://img.e-com-net.com/image/info8/84aa5c3d56014f0e80948c3aa6cc5878.jpg)
![博客作业06--图_第7张图片](http://img.e-com-net.com/image/info8/a93d316250ee4bcebb579fe524e0307a.jpg)
![1232047-20180616161140668-2101899557.png](http://img.e-com-net.com/image/info8/4fa50658ef144e699de8c14e9d3bb872.jpg)
1.2 图结构学习体会
- 深度遍历算法(DFS):一直往深处走,直到找到解或者走不下去为止;类似于树的先序遍历;利用递归(实质上是用栈来保存未访问的结点,先进后出)来实现比较简单;
- 广度遍历算法(BFS):利用队列(用队列来保存未访问的结点,先进先出)实现;类似于树的层次遍历;
- DFS 和 BFS 本质区别:BFS 的重点在于队列,而 DFS 的重点在于递归;
- Prim和Kruscal算法:寻找最小生成树,求最短路径;这两种算法的核心是并查集;一个是选点,一个是选边;当题中边的数目较为复杂时,选用prim算法;一般性问题,选kruscal算法,理解起来比较简单;
- Dijkstra算法:类似于Prim算法,唯一区别为:mindist[ ]的意义变为了原点到其他点的距离;这种算法只能解决权值不是负的图;特点:可以求出单源点到其他顶点的最短距离,算法的复杂程度比floyd算法稍微低一些;
- Floyd算法:时间复杂度比较高,不适合计算大量数据;特点:可以求多源最短路,权值同样不能为负;
- 拓扑排序算法:拓扑排序是针对有向无环图,基于队列来统计入度,先选择输出入度为0的点,删去该点及有关边,再依次循环处理其余点的入度;
- 算法比较多,需要理解并记忆,图比线性表和树更复杂,存储及遍历都需要记住,简单操作如建图、DFS、BFS;
2.PTA实验作业
2.1 题目1:7-1 图着色问题
- 对给定的一种颜色分配,请你判断这是否是图着色问题的一个解;
2.2 设计思路
- void DFS(MGraph g,int v);//深度遍历 void CreateMGraph(MGraph &g,int n,int e );//建图
- 伪代码:
定义变量n、e、k分别是无向图的顶点数、边、颜色数
定义数组 color[MAXV]={0}表顶点颜色并置零
sum 记录当前颜色总数目 ,标记变量 flag=0
数组c[MAXV]表 颜色类型
for i=1 to n
判断着色,不同,sum++
图的遍历:
if(颜色数sum不等于K) 不符合flag=1
else
通过邻接矩阵判断
2.3 代码截图
![博客作业06--图_第8张图片](http://img.e-com-net.com/image/info8/fe34d73c6eeb46b4a6b28a3351946b55.jpg)
2.4 PTA提交列表说明
![博客作业06--图_第9张图片](http://img.e-com-net.com/image/info8/0a4042817e7d4e749c4c72cdec8b2e0c.jpg)
- 部分正确;图不连通,DFS不重复访问顶点的错误,答案错误,图的建立需要顶点初始化,顶点、边数要赋值好;
- 答案错误;有小于K种颜色,题目中颜色数可能恰好相等,需要判断sum!=k;
2.1 题目2:7-3 六度空间
- 假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比;
2.2 设计思路
- int g[MAXN][MAXN]; //建图 int BFS(int i,int N); //对图进行广度遍历
- 伪代码:
双精度double sum 记录六度空间总数
queue Q; //用队列存放每层相邻顶点
标志数组 visit[MAXN]={0},层数level=0,tail记录最后顶点
对每个结点进行BFS,获取六度内的结点数sum
for i=1 to N
{
顶点相连且该顶点未被访问,入队,计数
tail 更新
}
一层层BFS,直到 level==6 break
输出: sum/(N*1.0)*100) //%%才能输出百分号
2.3 代码截图
![博客作业06--图_第10张图片](http://img.e-com-net.com/image/info8/7bb61df160ab48658482b6fc9483df61.jpg)
2.4 PTA提交列表说明
![1232047-20180616201500547-1370383601.png](http://img.e-com-net.com/image/info8/621cdab51fd44868aeb52adbc4c0548c.jpg)
- 在DEV-C运行正确后提交无误;
- 过程中错误:图初始化时,节点从1到N编号,图是从0开始的 ;
- 定义一个 last记录当前层访问的最后一个节点 ,查资料所得;%%才能输出百分号 ;
2.1 题目3:7-4 公路村村通
- 现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本;
2.2 设计思路
- int g[MAX][MAX]; //建无向图,以邻接矩阵进行存储 void Prim(int N); //普里姆算法
- 伪代码:
定义数组 lowcost[MAX]存放最低成本
定义变量 min,sum=0
lowcost[1] //序号为1的顶点出发
for i=0 to N-1 //找出N-1个顶点即可
{
min=INF;
for(j=1;j<=N;j++) // 找生成树距离最近的顶点
比min 小 更新
K记录最近顶点
sum=sum+lowcost[k];
}
2.3 代码截图
![博客作业06--图_第11张图片](http://img.e-com-net.com/image/info8/0beccf231bbe4666baeee70787da334d.jpg)
2.4 PTA提交列表说明
![1232047-20180616203837000-1650535275.png](http://img.e-com-net.com/image/info8/8e9a798098004db1b064291bcb834df4.jpg)
![博客作业06--图_第12张图片](http://img.e-com-net.com/image/info8/f22c86d732d14334bfa1da03a8a617a4.jpg)
- 段错误;M
- 答案错误;最大N和M,连通,在Prim()函数里面进行判断,加上if(i<=N) return -1;
- 答案错误;M达到N-1,但是图不连通,判断最小为无穷,则表示不连通, if(min==INF) return -1,前面改的也要变化;
3.截图本周题目集的PTA最后排名
3.1 PTA排名
![1232047-20180616205139520-812747852.png](http://img.e-com-net.com/image/info8/f33379fb8a2848619794fa1a953f6cee.jpg)
3.2 我的总分:221
4. 阅读代码
- 二分图匹配——棋盘游戏,题目链接:[https://blog.csdn.net/a1046765624/article/details/79440860]
- 代码:
#include
#include
#include
#include
#include
#include
#define MAXN 110
using namespace std;
int G[MAXN][MAXN];
int pipei[MAXN];
bool used[MAXN];
int N, M,K;
void init()
{
memset(G,0,sizeof(G));
}
void getMap()
{
int u,v;
for(int i = 0; i < K; i++)
{
scanf("%d%d",&u,&v);
G[u][v]=1;
}
}
int find(int x)
{
for(int i = 1; i <=M; i++)
{
int y = G[x][i];
if(y&&!used[i])
{
used[i] = true;
if(pipei[i] == -1 || find(pipei[i]))
{
pipei[i] = x;
return 1;
}
}
}
return 0;
}
int solve()
{
int ans = 0;
memset(pipei, -1, sizeof(pipei));
for(int i = 1; i <=N; i++)
{
memset(used, false, sizeof(used));
ans += find(i);
}
return ans;
}
int te=0;
int main()
{
while(~scanf("%d%d%d", &N,&M,&K))
{
te++;
init();
getMap();
int ans=solve();
int su;
int sum=0;
for(int i=1;i<=N;i++)
{
for(int j=1;j<=M;j++)
{
if(G[i][j])
{
G[i][j]=0;
su=solve();
if(su
- 代码思想:二分图匹配,匹配行和列,最后,搜索所有边,每次删除一条边,如果最大匹配变少了,这条边(就是棋盘位置)就是关键位置;
- 本题为二分图应用,有用到匈牙利算法,其本质就是寻找最大流的增广路径,本题中利用匈牙利算法求出最大匹配,即可放置的最大车的数量;
- 还有STL的应用,用STL中的 vector 建立邻接表实现匈牙利算法,效率比较高 ;
- 匈牙利算法有两种版本: DFS 和 BFS ,有利于我们结合所学进行联系比较学习;
- 二分图的最大匹配、完美匹配和匈牙利算法链接:[http://blog.jobbole.com/106084]
5.Git提交
![博客作业06--图_第13张图片](http://img.e-com-net.com/image/info8/e2e70b18d14a486cab891b1c96c78065.jpg)