1660: K-Cycle
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 124 Solved: 31
[ Submit][ Status][ Web Board]
Description
A simple cycle is a closed simple path, with no other repeated vertices or edges other than the starting and ending vertices. The length of a cycle is the number of vertices on it. Given an undirected graph G(V, E), you are to detect whether it contains a simple cycle of length K. To make the problem easier, we only consider cases with small K here.
Input
There are multiple test cases.
The first line will contain a positive integer T (T ≤ 10) meaning the number of test cases.
For each test case, the first line contains three positive integers N, M and K ( N ≤ 50, M ≤ 500, 3 ≤ K ≤ 7). N is the number of vertices of the graph, M is the number of edges and K is the length of the cycle desired. Next follow M lines, each line contains two integers A and B, describing an undirected edge AB of the graph. Vertices are numbered from 0 to N-1.
Output
For each test case, you should output “YES” in one line if there is a cycle of length K in the given graph, otherwise output “NO”.
Sample Input
2
6 8 4
0 1
1 2
2 0
3 4
4 5
5 3
1 3
2 4
4 4 3
0 1
1 2
2 3
3 0
Sample Output
YES
NO
HINT
Source
这是一个明显的dfs问题
只要找dfs到k的时候判读下能不能连回开始就可以了
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
const int M=55;
vector<int> e[M];
int isu[M];
int f;
void dfs(int ev,int nv,int now,int n,int k)
{
if(f)
return;
if(now==k)
{
for(int i=0;i<e[nv].size();i++)
if(e[nv][i]==ev)
{
f=1;
break;
}
return;
}
for(int i=0;i<e[nv].size();i++)
{
if(isu[e[nv][i]])
continue;
isu[e[nv][i]]=1;
dfs(ev,e[nv][i],now+1,n,k);
isu[e[nv][i]]=0;
}
}
int main()
{
int t;
int n,m,k;
int v1,v2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
f=0;
for(int i=0;i<n;i++)
e[i].clear();
memset(isu,0,sizeof(isu));
for(int i=0;i<m;i++)
{
scanf("%d%d",&v1,&v2);
e[v1].push_back(v2);
e[v2].push_back(v1);
}
for(int i=0;i<n;i++)
{
isu[i]=1;
dfs(i,i,1,n,k);
}
printf("%s\n",f?"YES":"NO");
}
return 0;
}
但是这个方法会超时,而且没想到什么好的剪枝方式
超时最主要的原因应该是每次判读能否连回起点是个很大的时间浪费,
用邻接矩阵的话这个判断会很容易,但是每次找边又会慢很多
而最关键的是确定起点后,中间很多的搜索过程并不能被重复利用
这个题目的具体做法相关的内容以前没有用过
无论是用邻接矩阵还是邻接表
都不是这个题目超时的原因
这个题目其实可以这样来做
每个点在dfs到的时候记录一个深度,如果dfs到已经到过的点那么判断两次到达的深度差是不是k如果是说明形成了环
这样dfs做一次就能解决dfs过的点的问题
时间也会大大节省
如下
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
const int M=55;
vector<int> e[M];
int isu[M];
int f;
void dfs(int nv,int now,int n,int k)
{
if(f)
return;
if(isu[nv])
{
if(now-isu[nv]==k)
f=1;
return;
}
isu[nv]=now;
for(int i=0;i<e[nv].size();i++)
{
dfs(e[nv][i],now+1,n,k);
}
}
int main()
{
int t;
int n,m,k;
int v1,v2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
f=0;
for(int i=0;i<n;i++)
e[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d",&v1,&v2);
e[v1].push_back(v2);
e[v2].push_back(v1);
}
for(int i=0;i<n;i++)
{
memset(isu,0,sizeof(isu)); //这个memset仔细思考了下是不是非要放在for里面
dfs(i,1,n,k);
}
printf("%s\n",f?"YES":"NO");
}
return 0;
}
测试的结果是不放在for里面也可以ac
但是,我觉得某个点不是开始的构成环情况,好像并不一定会在别的点dfs中遍历完全
这里留下一个思考