uva 208 Firetruck (需要预先处理 再dfs,TLE是此题AC常规步骤……)

来源:互联网 发布:最游记一键淘宝端 编辑:程序博客网 时间:2024/04/30 15:29

刚开始读完题目时感觉题目很常规,感觉就是很简单的连通图遍历,从起点遍历到终点,然后打印路径而已。

于是乎,用dfs理智的敲了一遍,然后TLE……

其实看到那么低的通过率就应该想到不会这么简单的。。不过对于一遍TLE这个伟大的事件,还是应该表扬一下,避免了走很多弯路。。

TLE之后马上就意识到这道题目不简单……一心想着自己的算法看来使用错了,一定会有大神用牛逼的算法来秒这道题!想着反正我的dfs没问题,算法错了让我如何是好!求知心切,就立马去看了其中的玄机……然后发现没有玄机。。就是在dfs之前先找出和终点连在一起的点将其记录下来,这样就可以避免dfs时会浪费大量的时间去回溯那些不可能到达终点的点了。大神管这个叫 “剪枝”。。。好吧,那我就学着 剪枝 了一下。。然后AC。。

为什么说这道题目好嘞?因为这道题目的亮点就在于为我提供了一条思路——当你dfs超时了,你该怎么办——剪枝!想各种办法剪枝!

而且这里还直接教了一种剪枝的办法,就实现从终点深搜一遍,找出能够到达终点的点,就能排除那些不必要的回溯时间。深搜不回溯,要比在没意义的点上不停地来来回回遍历要省时多了,根本不是一个数量级……

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm>using namespace std;int n;int G[25][25];int vis[25];int r[22];int ok[22],count_;int t1,t2,cnt;int route[100000][22];void dfs_init(int u){    ok[count_++]=u;    vis[u]=1;    for(int v=1;v<=21;v++)    {        if(G[u][v]&&!vis[v])            dfs_init(v);    }}void dfs(int u){    vis[u]=1;    if(u==n)    {        cnt++;        memcpy(route[t2++],r,sizeof(r));        t1--;        vis[u]=0;        return;    }    for(int i=0;i<count_;i++)    {        int v=ok[i];        if(G[u][v]&&!vis[v])        {            r[t1++]=v;            G[u][v]=G[v][u]=0;            dfs(v);            G[u][v]=G[v][u]=1;        }    }    vis[u]=0;    t1--;    return;}int main(){    int k=1;    while(scanf("%d",&n)!=EOF)    {        memset(G,0,sizeof(G));        memset(route,0,sizeof(route));        int a1,a2;        while(scanf("%d%d",&a1,&a2)!=EOF)        {            if(a1==0&&a2==0)                break;            G[a1][a2]=G[a2][a1]=1;        }        memset(vis,0,sizeof(vis));        count_=0;        dfs_init(n);        sort(ok,ok+count_);        memset(vis,0,sizeof(vis));        t2=cnt=0;        r[0]=1;        t1=1;        dfs(1);        printf("CASE %d:\n",k++);        for(int i=0;i<cnt;i++)        {            for(int j=0;route[i][j]!=n;j++)            {                printf("%d ",route[i][j]);            }            printf("%d",n);            printf("\n");        }        printf("There are %d routes from the firestation to streetcorner %d.\n",cnt,n);    }    return 0;}

其实上面的代码还有一个缺点,就是开了没有必要的大数组……,路劲根本就没有必要存下来,可以在dfs的时候直接输出来就好……浪费内存,也会浪费一部分时间、。。

向下面这样会很省内存,不用担心数组开小了,也不用担心内存不够。而且经验证真的会省不少时间,用时是上面的1/5……

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm>using namespace std;int n;int G[25][25];int vis[25];int r[22];int ok[22],count_;int t1,t2,cnt;void dfs_init(int u){    ok[count_++]=u;    vis[u]=1;    for(int v=1;v<=21;v++)    {        if(G[u][v]&&!vis[v])            dfs_init(v);    }}void dfs(int u){    vis[u]=1;    if(u==n)    {        cnt++;        for(int i=0; i<t1-1; i++)        {            printf("%d ",r[i]);        }        printf("%d\n",n);        t1--;        vis[u]=0;        return;    }    for(int i=0;i<count_;i++)    {        int v=ok[i];        if(G[u][v]&&!vis[v])        {            r[t1++]=v;            G[u][v]=G[v][u]=0;            dfs(v);            G[u][v]=G[v][u]=1;        }    }    vis[u]=0;    t1--;    return;}int main(){    int k=1;    while(scanf("%d",&n)!=EOF)    {        memset(G,0,sizeof(G));        int a1,a2;        while(scanf("%d%d",&a1,&a2)!=EOF)        {            if(a1==0&&a2==0)                break;            G[a1][a2]=G[a2][a1]=1;        }        memset(vis,0,sizeof(vis));        count_=0;        dfs_init(n);        sort(ok,ok+count_);        memset(vis,0,sizeof(vis));        t2=cnt=0;        r[0]=1;        t1=1;        printf("CASE %d:\n",k++);        dfs(1);        printf("There are %d routes from the firestation to streetcorner %d.\n",cnt,n);    }    return 0;}

。哦,还有那个sort不能少的~否则不是字典序输出。

2 0
原创粉丝点击