您的位置:首页 > 其它

CSU 1660 搜索 在图中寻找一个长度为K的环

2016-08-11 14:22 316 查看
      题目的大概意思就是在给出的图里面寻找一个长度为K的环。。。

      想了一想,肯定是用DFS,然后就考虑实现,可是以什么作为参数呢,以下是我考虑不恰当的地方:

      我考虑的DFS参数有3个,第一个是当前的位置,还有一个是余剩的步数(我想到最多只能够走K次),还有一个是此次搜索的起点。

      剪枝:跳过度为1的点,因为度为1的点不可能处于环上

      我自己也认识到,这样的搜索有很大的重复性,比方说我从一个节点A向下寻找,在K步之内没有找到,接下来我会去在A+1处调用DFS,假若A和A+1相邻,此时所做的很大一部分工作是重复的,因为从A向A+1这边搜索的时候,已经搜索过一部分了,现在再搜索也仅仅是比原来多走一步而已。我想把走过的步数记录下来,可是没有想到好的办法,结果TLE到比赛结束。

  比赛完之后去看题解发现自己没法实现的东西轻易的就可以实现。。。不得不说有点遗憾?

  这个DFS里面有三个参数,第一个是当前的节点,第二个是离源节点的步数,第三个是父节点(也就是从哪边过来的)

  在DFS搜索里面用来表示是否访问过的VIS数组来表示这个是离调用点有多少步,访问到某一个点P时,假若P已经访问过了,那么就把VIS里保存的步数取出来和当前的步数相比较,假若是K的话,那么就表明经过了一个环了。假若不是K,那么继续调用DFS。

  这样的好处是一次可以搜索完一个连通子图,而不用像我之前那样对每一个节点都调用,显然要少做很多的重复性工作。以下是AC的代码,同样有跳过度为1的点的剪枝

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

vector<int> v[55];
int vis[55],n,m,x,y,t,k;
bool flag,_find(int now,int pos,int pre);

int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<m;++i)
scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);

for(int i=0;i<n;++i)
if(v[i].size()>1&&_find(i,1,-1))
flag=true,i=n;

printf("%s\n",(flag)?"YES":"NO");
flag=false;memset(vis,0,sizeof(int)*n);
for(int i=0;i<n;++i)
v[i].clear();
}
return 0;
}

bool _find(int now,int pos,int pre){
if(vis[now])
return pos-vis[now]==k;
vis[now]=pos;
for(int i=0;i<v[now].size();++i)
if(v[now][i]!=pre&&v[v[now][i]].size()>1&&_find(v[now][i],pos+1,now))
return true;
return false;
}


  为了做比较,我把之前的TLE的代码也贴出来

#include<cstdio>
#include<vector>
#include<cstring>

using namespace std;

int t,n,m,k,x,y;

vector<int> v[55];
bool _find(int pos,int remain,int recourse),flag=false;
int visi[55];

int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<m;++i)
scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
//printf("%d\n",v[0].size());
for(int i=0;i<n;++i)
if(v[i].size()>1&&_find(i,k,i)){
flag=true;
break;
}
printf("%s\n",(flag)?"YES":"NO");
for(int i=0;i<n;++i)
v[i].clear();
flag=false;memset(visi,0,sizeof(visi));
}
return 0;
}

bool _find(int pos,int remain,int recourse){
if(remain<=0)
return false;
visi[pos]=1;
for(int i=0;i<v[pos].size();++i){
if(visi[v[pos][i]]==1&&v[pos][i]==recourse&&remain==1)
return true;
else if(v[v[pos][i]].size()>1&&visi[v[pos][i]]==0){
if(_find(v[pos][i],remain-1,recourse))
return true;
}
}
visi[pos]=0;
return false;
}


  这样写完之后,感觉自己的想法也清晰了很多。。

       补充:虽然我说的第一种解法很好,可是第一种解法是仅仅针对于部分的情况,由于CSUOJ的数据的问题,导致有一些情况无法正常的判断出来,比如说http://blog.csdn.net/nameofcsdn/article/details/52184252 这儿的给出的一个数据反例,经测试我说的AC代码是无法正常运行出正确的结果,可是用我原来的搜索代码就可以得到正确的答案,看来我考虑问题还是应该要深入一些才好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  CSU1660 搜索
相关文章推荐