hdu3816 dfs剪枝

本文探讨了一种编程挑战中遇到的问题——在处理大量数据时导致的超时错误。通过优化算法和剪枝策略,作者成功地提高了程序的效率,避免了不必要的计算并确保了算法在合理时间内完成任务。文章详细介绍了实现这一优化的方法,包括字符串排序、图论应用、深度优先搜索等关键步骤,以及如何预判和处理不连通的节点以减少计算负担。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题做的好郁闷啊

题意:很像以前做过的成语接龙,不过比那个难度大点,他是一次输入两个词,然后只要把这些词连起来就行了,起点为sea,终点为sky

 

这题用到了很多剪枝:

1.把多余的字符串去掉,然后按照升序排序,然后根据你输入的每次两个词,使他们连通起来,构建成一个图,这样每次得到的都是按照字典排序好的

2.预先判断图是否连通,不连通直接输无法找到

3.找出所有不连通的点,这样在进行dfs时,可以节省好多时间。

 

自己花了点时间写了个代码:

#include<cstdio>
#include<cstring>

char word[20][20];
int n,wcount,m;
int map[20][20];
int vis[20],path[20],tmpPath[20],no[20],vis2[20];
int mDeep,start,end;


int getWord(char *s){
    for(int i=0;i<wcount;i++){
        if(strcmp(s,word[i])==0){
            return i;
        }
    }
    strcpy(word[wcount++],s);
    
    return wcount-1;
}

void dfs(int pos,int deep){
    if(deep>wcount){
        return;
    }
    
    tmpPath[deep]=pos;
    if(pos==end){
        
        if(mDeep<deep){
            mDeep=deep;
            memcpy(path,tmpPath,deep*sizeof(int));
        }
        if(mDeep==wcount){
        return;
    }
        return;
    }
    
    for(int i=0; i<wcount; i++){
        
        if(map[pos][i]&&!vis[i]){
            //printf("%d %d\n",pos,i);
            vis[i]=1;
            dfs(i,deep+1);
            if(mDeep==wcount){
                return;
            }
            vis[i]=0;
        }
        
    }
    
}

//剪枝 ,判断点是否可达 
int dfs2(int pos,int zd){
    if(pos==zd){
        return true;
    }
    for(int i=0;i<wcount;i++){
        if(!vis2[i]&&map[pos][i]&&!vis[i]){
            vis2[i]=1;
            if(dfs2(i,zd)){
                return true; 
            } 
        }
        
    }
    return false;
    
}

int main(){
    int T;
    char s1[100][20],s2[100][20];
    scanf("%d",&T);
    
    for(int t=0;t<T;t++){
        scanf("%d",&n);
        //初始化 
        wcount=0;
        memset(map,0,sizeof(map));
        memset(vis,0,sizeof(vis));
        mDeep=0;
        for(int i=0;i<20;i++){
            strcpy(word[i],"\0");
        }
        
        //储存单词 
        for(int i=0;i<n;i++){
            scanf("%s%s",&s1[i],&s2[i]);
            //printf("%s %s\n",s1,s2);
            getWord(s1[i]);
            getWord(s2[i]);
        }
        //排序 
        char c[20];
        for(int i=1;i<wcount;i++){
            for(int j=0;j<i;j++){
                if(strcmp(word[i],word[j])<0){
                    strcpy(c,word[i]);
                    strcpy(word[i],word[j]);
                    strcpy(word[j],c);
                }
            }
        }
        
        
        
        //构建图 
        int a,b;
        for(int i=0;i<n;i++){
            a=getWord(s1[i]);
            b=getWord(s2[i]);
            map[a][b]=map[b][a]=1;
            //printf("%d %d\n",a,b);
        }
        
        //寻找起点和终点 
        for(int i=0;i<wcount;i++){
            if(strcmp(word[i],"sea")==0){
                start=i;
            }
            else if(strcmp(word[i],"sky")==0){
                end=i;
            }
        }
        vis[start]=1;
        memset(vis2,0,sizeof(vis2));
        printf("Case %d: ",t+1);
        if(!dfs2(start,end)){
            printf("what a pity\n"); 
            continue;
        }
        
        //去掉不能到达终点的点 
        for(int i=0;i<wcount;i++){
            memset(vis2,0,sizeof(vis2));
            if(!vis[i]){
                if(!dfs2(i,end)){
                    vis[i]=1;
                }
            }
        }
        vis[start]=0;
        
        vis[end]=1;
        //去掉不能到达起点的点
        for(int i=0;i<wcount;i++){
            memset(vis2,0,sizeof(vis2));
            if(!vis[i]){
                if(!dfs2(i,start)){
                    vis[i]=1;
                }
            }
        } 
        vis[end]=0;
        memset(vis2,0,sizeof(vis2));
        
        
        vis[start]=1;
    
    
        dfs(start,0);
        for(int i=0;i<mDeep;i++){
            if(i==0){
                printf("%s",word[path[i]]);
            }
            else{
                printf(" %s",word[path[i]]);
            }
        }
        printf(" sky");
        
        printf("\n");
        
    }
    return 0;
}


可是发现老是tle,这都快郁闷死了,明明可以过的,时间复杂度和下面的代码是一样的,可是换成下面的代码31ms就过了,真郁闷啊

#include <cstdio>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <cstdlib>
using namespace std;
char word[20][20],s1[105][20],s2[105][20];
int ws,map[20][20],vis[20],vis2[20],res[20],bres[20],yes,sky,sea,rl;
void init(){
    memset(map,0,sizeof map);
    for(int i=1;i<=20;i++)strcpy(word[i],"\0");
    ws=0;//点数  
    memset(res,0,sizeof res);
    yes=0;
    rl=0;
}
//搜连通 
int dfslt(int p){
    if(p==sky)return 1;
    for(int i=1;i<=ws;i++){
        if(!vis[i]&&map[p][i]){
            vis[i]=1;
            if(dfslt(i))return 1;    
        }    
    }
    return 0;
}
//搜不可到达的点 
int dfs2(int p,int dir){
    if(p==dir)return 1;
    for(int i=1;i<=ws;i++){
        if(!vis2[i]&&!vis[i]&&map[p][i]){
            vis2[i]=1;
            if(dfs2(i,dir))return 1;    
        }    
    }
    return 0;    
}
int dfs(int step,int p){
    if(step>ws)return 0;
    if(res[step]==sky&&step>rl){
        yes=1;
        rl=step;
        for(int i=0;i<=rl;i++){
            bres[i]=res[i];    
        }
        if(rl==ws)return 1;
        return 0;    
    }
    for(int i=1;i<=ws;i++){
        if(!vis[i]&&map[p][i]==1){
            vis[i]=1;
            res[step+1]=i;
            if(dfs(step+1,i))return 1;
            vis[i]=0;    
        }    
    }
    return 0;
}

int gwords(char *ss){
    for(int i=1;i<=ws;i++){
        if(strcmp(word[i],ss)==0){
            return i;
        }
    }
    ws++;
    strcpy(word[ws],ss);
    return ws;
}

int main(){
    int cas;
    scanf("%d",&cas);
    for(int ca=1;ca<=cas;ca++){
        init();
        int n,a,b;
        scanf("%d",&n);
        //输入字符串 储存 
        for(int i=1;i<=n;i++){
            scanf("%s%s",s1[i],s2[i]);
            gwords(s1[i]),gwords(s2[i]);
        }
        //冒泡排序 
        char t[20];
        for(int i=1;i<=ws-1;i++){
            int ind=i;
            for(int j=i+1;j<=ws;j++){
                if(strcmp(word[j],word[ind])<0)ind=j;    
            }
            if(ind!=i){
                strcpy(t,word[ind]);
                strcpy(word[ind],word[i]);
                strcpy(word[i],t);    
            }
        }
        //建图 map[i][j]~按照字符串升序 
        for(int i=1;i<=n;i++){
            a=gwords(s1[i]),b=gwords(s2[i]);
            map[a][b]=map[b][a]=1; 
        }        
        
        
        //判单词是否存在
        sky=-1,sea=-1;
        for(int i=1;i<=ws;i++){
            if(strcmp(word[i],"sky")==0)sky=i;
            if(strcmp(word[i],"sea")==0)sea=i;    
        } 
        //判sea->sky是否可达 
        memset(vis,0,sizeof vis);
        vis[sea]=1;
        //如果不存在单词 或者两者不可达 
        if(sky==-1||sea==-1||!dfslt(sea)){
            printf("Case %d: what a pity\n",ca);
            continue;    
        }
        memset(vis,0,sizeof vis);
        
        //强力剪枝,去掉不可到达的点 
        for(int i=1;i<=ws;i++){
            memset(vis2,0,sizeof vis2);
            vis2[sea]=1;
            if(!dfs2(i,sky))vis[i]=1;
        }
        for(int i=1;i<=ws;i++){
            memset(vis2,0,sizeof vis2);
            vis2[sky]=1;
            if(!dfs2(i,sea))vis[i]=1;
        }    
        
        //搜索 
         
        vis[sea]=1;
        res[1]=sea;
        dfs(1,sea);
        //输出    
        if(yes){
            printf("Case %d: %s",ca,word[bres[1]]);
            for(int i=2;i<=rl;i++){
                printf(" %s",word[bres[i]]);
            }
            printf("\n");            
        }else{
            printf("Case %d: what a pity\n",ca);
        }
        
    }
    return 0;    
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值