P3916 图的遍历

  这是一道很简单的模版题(尽管我调了好长时间)……QAQ

  那那那就总结思路嘞:

  乍一看,觉得dfs就可以,于是便有这样的代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int to[100005],head[100005],nxt[100005],cnt;
bool b[100005];
int sum;
int n,m;
void add(int a,int t)
{
    cnt++;
    to[cnt]=t;
    nxt[cnt]=head[a];
    head[a]=cnt;
}
void dfs(int x)
{
    for(int i=head[x]; i; i=nxt[i])
    {
        if(b[to[i]]==0)
        {
            b[to[i]]=1;
            sum=max(sum,to[i]);
            dfs(to[i]);
            b[to[i]]=0;
        }
        else
        return ;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int a,t;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&a,&t);
        add(a,t);
    }
    for(int i=1; i<=n; i++)
    {
        memset(b,0,sizeof(b));
        sum=0;
        b[i]=1;
        dfs(i);
        sum=max(sum,i);
        printf("%d ",sum);
    }
    return 0;
}

  但是呐,这个代码其实有很大漏洞的,那就是:

void dfs(int x)
{
    for(int i=head[x]; i; i=nxt[i])
    {
        if(b[to[i]]==0)
        {
            b[to[i]]=1;
            sum=max(sum,to[i]);
            dfs(to[i]);
            b[to[i]]=0;
        }
        else
        return ;
    }
}

  

  在这里,只要有一个b[]没满足dfs就会返回,会遗漏情况…另外,above all,会超时…

  那么怎么不超时呐???

       特别鸣谢ssy等人的鼎力支持,使蒟蒻的我想到一个全新的方案,我们可以逆向思考:那就是从后往前找!!!(震惊!)

  还有这种操作???

  是的!

  代码呈现:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int to[100005],head[100005],nxt[100005],cnt;
bool b[100005];
int sum,ans[100005],now;
int n,m;
void add(int a,int t)
{
    cnt++;
    to[cnt]=t;
    nxt[cnt]=head[a];
    head[a]=cnt;
}
void dfs(int x)
{    
    if(ans[x])
        return ;
    ans[x]=now;
    for(int i=head[x];i;i=nxt[i])
    {
        if(ans[to[i]]==0)
            dfs(to[i]);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int a,t;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&a,&t);
        add(t,a);
    }
    for(int i=n;i>=1;i--)
    {
        memset(b,0,sizeof(b));
        now=i;
        dfs(now);
    }
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}

  

  假设有10个点,那么从10这个点往回找,只要能到达,就给这个点赋上值,那么下一次搜9的时候,赋值的点一定是最优点,碰到就直接return,如果没赋值,则证明这个点不能到10,最优解一定是9。这样使不必要的情况被有效避免,就达到了剪枝的目的。注意add要反过来。

  >\<~

原文地址:https://www.cnblogs.com/popo-black-cat/p/10028299.html