图
2018-06-18 15:02 工班 阅读(218) 评论(1) 编辑 收藏 举报
---恢复内容开始---
1、思维导图
2、图的学习体会
(1)首先理解图的定义,有顶点和边组成,所有的定点的度之和等于边数的两倍,完全无向图的边为n(n-1)/2;完全有向图n(n-1);图还分为稠密图和疏密图;
强连通图有n个顶点,n条边,最多有n(n-1)条边。无向图n个顶点至少n条边。
(2)邻接矩阵:无向图,一定对称。有向图,可能对称,可能不对称。图的邻接矩阵表示是唯一的。对于含有n个顶点的图,采用邻接矩阵存储,比较适合稠密图
(3)无向图的邻接矩阵一定是一个对称矩阵。
(4)用邻接矩阵方法储存图,很容易确定图中任意两个顶点之间是否有边相连。
(5)邻接表表示不唯一
(6)DFS深度优先遍历,BFS广度优先遍历用队列结构。
(7)一个连通图的最小生成树不一定唯一,权值之和一定相同。
(8)有向无环,还可用深度优先遍历算法,邻接表。AOE网带权的有向无环图。
但是编译、运行代码的有点困难,理解起来太困难,学了之后有点混乱,不过我会努力去理解,多多练习。
2 、PTA实验练习
题目一
2.1图着色问题
1·设计思路
先建立一个无向图,包括顶点,边,颜色数的定义名称,然后顶点和颜色都从1到V编号。
随后E行,每行给出一条边的两个端点的编号。
把图建好后int一个正整数n,代表待检查的颜色分配方案的个数。
随后N行,每行顺次给出V个顶点的颜色(第i个数字表示第i个顶点的颜色)
无向图是合法的(不存在自回路和重边)
建一张图存储关系,查集求出是朋友的人,然后在图中将并查集中的点都连边,最后判断边的权值
2·伪代码
int i,j;
scanf("%d%d%d",&n,&m,&k);
int u,v;
tot=0;
memset(mp,0,sizeof(mp));
while(m--){
scanf("%d%d",&u,&v);
mp[u][v]=mp[v][u]=1;
}
scanf("%d",&t);
while(t--){
int sum=0;
flag=1;
memset(viscolor,0,sizeof(viscolor));
for(i=1;i<=n;i++){
scanf("%d",&color[i]);
if(!viscolor[color[i]]){
sum++;
viscolor[color[i]]=1;
}
}
if(sum!=k){
printf("No\n");
continue;
}
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++){
if(!vis[i]){
if(!flag)
break;
vis[i]=0;
dfs(i);
}
}
如果flag=1;
输出No;
else
输出Yes
}
3·代码截图
4·PTA提交说明
题目二
2.2排座位
1、设计思路
输入第一行给出3个正整数:N(
前来参宴的宾客总人数)则这些人从1到N
编号;M
为已知两两宾客之间的关系数;K
为查询的条数。随后M
行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系
,其中关系
为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K
行,每行给出一对需要查询的宾客编号
2、伪代码
先输入fa[MAX];
int 函数Find(int a)
{
如果 fa[a]等于a
返回 a;
否则 返回 Find(fa[a]);
}
void 函数Union(int a,int b)
{
int faa=Find(a)赋值;
int fab=Find(b);
if(faa==fab)
return ;
fa[faa]=fab;
}
int main()
{
打开文件stout和stdin
int N,M,K;
while(scanf("%d%d%d",&N,&M,&K)!=0)
{
memset(g,0x3f,sizeof(g));
for(int i=1;i<=N;i++)
fa[i]=i;
while(M--)
{
int a,b,r;
scanf("%d%d%d",&a,&b,&r);
if(r==1)
{
g[a][b]=g[b][a]=1;
Union(a,b);
}
else if(r==-1)
{
g[a][b]=g[b][a]=-1;
}
}
for(int i=1;i<=N;i++)
{
Set[i].clear();
for(int j=1;j<=N;j++)
{
if(Find(j)==i) Set[i].push_back(j);
}
}
for(int i=1;i<=N;i++)
{
for(vector<int>::iterator j=Set[i].begin();j!=Set[i].end();j++)
{
for(vector<int>::iterator k=Set[i].begin();k!=Set[i].end();k++)
{
如果g[*j][*k]等于-1
g[*j][*k]等于0;
else if(g[*j][*k]==INF)
g[*j][*k]等于1;
如果g[*k][*j]等于-1
g[*k][*j]等于0;
else if(g[*k][*j]==INF)g[*k][*j]=1;
}
}
}
for(int i=0;i<K;i++)
{
int a,b;
输入("%d%d",&a,&b);
如果g[a][b]等于1
输出No problem;
else if(g[a][b]==-1) 输出No way;
else if(g[a][b]==0) 输出OK but...;
else if(g[a][b]==INF) 输出"OK;
}
}
3、代码截图
4、PTA提交说明
题目三
2·3公路村村通
1、设计思路
prim算法求最小生成树,从 1 开始;
2、伪代码
void prim(const int N){
collected[1] = 1; //以1号结点作为开始
while (ture) {
定义minPos,MinDist;
minPos 返回-1;
MinDist返回INF;
for(int i=1; i<=N; i++){
if(collected[i]==0 && dist[i]<minDist){
minPos 等于 i;
minDist 等于dist[i];
}
}
如果minPos 等于 -1
用break结束;
collected[minPos] 等于 1;
minCost 等于 minCost+dist[minPos];
for(int i=1; i<=N; i++){
如果collected[i]恒等于0 并且 graph[minPos][i]小于dist[i]{
dist[i] 等于 graph[minPos][i];
}
}
}
3、代码截图
4、PTA提交说明
三、截图本周题目集的PTA最后排名
四、阅读代码
#include <iostream>
#include <cstring>
#include <set>
using namespace std;
int v, e, k;
int map[501][501] = {0};
int color[501] = {0};
bool flag = true;
bool vis[501];
void isYes(int i)
{ if (vis[i] || flag == false)
{ return; }
vis[i] = true;
for (int j = 0; j < v;j++)
{ if (color[i] == color[j] && map[i][j] == 1)
{ flag = false; return; }
else if (map[i][j] == 1 && vis[j] == false
){ isYes(j); } } }
int main()
{ cin >> v >> e >> k;
for (int i = 0; i < e; i++)
{ int x, y; cin >> x >> y; x--;
y--; map[x][y] = 1;
map[y][x] = 1; }
int m; cin >> m;
for (int i = 0; i < m; i++)
{ set<int> s;
for (int j = 0; j < v; j++)
{ int c; cin >> c; s.insert(c);
color[j] = c; }
if (s.size() != k)
{ flag = false; }
else { memset(vis, false, sizeof(vis));
flag = true; for (int j = 0; j < v; j++)
{ isYes(j); if (flag == false) { break; } } }
if (flag) { cout << "Yes" << endl; }
else { cout << "No" << endl; } }
return 0; }
这个代码是从网上搜的,比我的代码简短,直接用图的遍历,遍历的时候判断是否颜色相等即可。
注意需要不同颜色的个数需要等于k
---恢复内容结束---