PAT甲级-1154 Vertex Coloring (25 分) ( set + 枚举 / dfs )

这篇博客介绍了如何解决无向图的k-染色问题,即判断是否存在一种染色方案使得相邻节点颜色不同。提供了两种检查方法:一是遍历所有边检查相邻节点颜色,二是使用深度优先搜索。代码实现中展示了这两种方法,并给出了相应的C++代码示例。
题目链接:点击进入
题目

在这里插入图片描述
在这里插入图片描述

题意

大概就是 n 点 m 边的无向图 ( 不一定联通 ) ,给你每个点的颜色,让你判断 k - 染色图 ( 就是相邻两点不能同色,所有点最多 k 种颜色的图 ) ,是输出 k ,不是输出 No

思路

k 染色图,这个 k 可以将所有点的颜色插入 set 来求,判断相邻两点是否同色有两种方法。
第一种 ( 简单 ):枚举每条边,判断两个端点是否同色;
第二种:枚举每个连通块,dfs 判断里面每条边两端是否同色。
两种方式结果相同,第一种简单点。

代码1
#include<iostream>
#include<map>
#include<set>
#include<cstring>
using namespace std;
const int maxn=1e5+10;

int n,m,k,a[maxn];
struct node
{
	int x;
	int y;
}p[maxn];
set<int>s;


int main( )
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>p[i].x>>p[i].y;
	cin>>k;
	while(k--)
	{
		s.clear();
		for(int i=0;i<n;i++)
			cin>>a[i],s.insert(a[i]);
		int flag=0;
		for(int i=1;i<=m;i++)
		{
			if(a[p[i].x]==a[p[i].y])
			{
				flag=1;
				break;
			}
		}
		if(!flag)
			cout<<s.size()<<"-coloring"<<endl;
		else
			cout<<"No"<<endl;
	}
	return 0;
}
代码2
#include<iostream>
#include<map>
#include<set>
#include<cstring>
using namespace std;
const int maxn=1e5+10;

int n,m,k,head[maxn],tot,a[maxn],flag;
bool vis[maxn];
struct node
{
	int to;
	int next;
}edge[maxn];
set<int>s;

void init()
{
	memset(head,-1,sizeof(head));
	tot=0;
}
void add(int u,int v)
{
	edge[tot].to=v;
	edge[tot].next=head[u];
	head[u]=tot++;
}
void dfs(int pos,int fa)
{
	vis[pos]=1;
	for(int i=head[pos];i!=-1;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa) continue;
		if(a[v]==a[pos]) flag=1;
		if(flag) return ;
		if(vis[v]) continue;
		dfs(v,pos);
	}
}

int main( )
{
	init();
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	cin>>k;
	while(k--)
	{
		s.clear();flag=0;
		for(int i=0;i<n;i++) vis[i]=0;
		for(int i=0;i<n;i++)
			cin>>a[i],s.insert(a[i]);
		for(int i=0;i<n;i++)
		{
			if(!vis[i]) dfs(i,-1);
			if(flag) break;
		}
		if(!flag)
			cout<<s.size()<<"-coloring"<<endl;
		else
			cout<<"No"<<endl;
	}
	return 0;
}
<think>好的,我现在需要仔细析用户提供的C代码,并回答他们的问题。首先,用户给出的代码是关于图的邻接矩阵表示以及深度优先搜索(DFS)的实现。看起来用户可能在询问代码中的问题或者希望了解如何改进或理解其工作原理。 首先,我会通读整个代码,检查是否有语法错误、逻辑错误或潜在的问题。让我逐步析: 1. **结构定义部**: - 定义了顶点类型为`char`,边类型为`int`,邻接矩阵的大小是MAXSIZE=100。 - 结构体`Mat_Grph`包含顶点数组、邻接矩阵、顶点数和边数。 2. **创建图的函数`create_gragh`**: - 设置顶点数为9,边数为15。然后初始化顶点为'A'到'I'(因为i从0到8)。 - 初始化邻接矩阵为全0。 - 接着根据注释添加边,比如A-B对应arc[0][1]和arc[1][0]设置为1。但这里有一个问题:代码中在设置完所有边之后,又通过循环将邻接矩阵转置,使得arc[j][i]等于arc[i][j]。这一步是否正确?比如,原来的arc[0][1]被设置为1,之后在循环中,arc[1][0]也会被设置为arc[0][1]的值,即1。但因为前面已经手动设置了对称的边,比如arc[1][2] = 1后,又会重复设置arc[2][1] = 1。这可能导致重复操作,但可能不影响结果,因为都是1。不过,如果前面的边没有对称设置,比如如果只设置arc[i][j]而不设置arc[j][i],那么后面的循环会补全。但在这个代码中,用户是否在手动设置时已经处理了双向边?比如,A-B的设置是arc[0][1] =1,而没有arc[1][0]。此时后面的循环会补全,所以最终邻接矩阵是对称的。这部可能没问题。 3. **DFS函数**: - 使用递归实现DFS,访问顶点i后,遍历所有顶点j,检查arc[i][j]是否为1且visited[j]是否为0。但这里有一个明显的错误:在if条件中,用户写的是`visited[i] == 0`,而应该是检查`visited[j] == 0`。因为当前访问的是i,而下一个要访问的是j,所以应该判断j是否被访问过。这个错误会导致DFS无法正确遍历所有节点,甚至可能进入无限递归或错误地跳过节点。 4. **主函数**: - 创建图,初始化visited数组,然后从顶点0(即'A')开始DFS。 现在,用户的问题可能在于代码运行不正确,或者DFS没有按预期遍历所有节点。例如,当运行DFS时,由于条件错误,可能无法访问到某些节点,或者程序崩溃。 所以,用户的问题可能围绕代码中的错误,尤其是DFS函数中的条件错误。我需要指出这个错误,并提供修正方法。此外,可能还需要解释代码的其他部,如邻接矩阵的构造是否正确,DFS的递归实现是否合理等。 接下来,我需要根据用户的需求,给出答案,并生成相关问题。根据示例,回答后需要列出3-5个相关问题,格式正确。</think>在提供的代码中存在一个关键错误,导致深度优先搜索(DFS)无法正确遍历图的连通部。具体问题出在`dfs`函数的条件判断上: ```c if(G.arc[i][j] == 1 && visited[i] == 0) ``` **错误析**: 此处的`visited[i] == 0`应为`visited[j] == 0`。当前代码在访问顶点`i`后,错误地检查`i`是否未被访问,而实际应判断邻接顶点`j`是否未被访问。此错误会导致: 1. 若`i`已被访问(`visited[i] == 1`),条件不成立,无法继续探索邻接点`j`; 2. 若`i`未被访问(`visited[i] == 0`),即使`j`已被访问,仍可能触发递归,导致逻辑混乱。 **修正代码**: ```c void dfs(Mat_Grph G, int i) { visited[i] = 1; printf("%c\n", G.vertex[i]); for (int j = 0; j < G.vertex_num; j++) { if (G.arc[i][j] == 1 && visited[j] == 0) // 修改为判断visited[j] { dfs(G, j); } } } ``` **其他注意事项**: 1. 邻接矩阵的对称性:代码通过循环补全了邻接矩阵的对称性(`G->arc[j][i] = G->arc[i][j];`),确保无向图的正确表示。 2. 顶点数限制:`MAXSIZE`设为100,但实际仅使用前9个顶点('A'-'I'),未越界。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值