CSU_1660_K-Cycle

18 篇文章 0 订阅
16 篇文章 0 订阅

1660: K-Cycle

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 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;
}


上面的memset是不是一定要放在for里面

测试的结果是不放在for里面也可以ac

但是,我觉得某个点不是开始的构成环情况,好像并不一定会在别的点dfs中遍历完全

这里留下一个思考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值