UVA208(Firetruck)

//终于有一天,Leosu想起了自己的简书密码。。
题目就不复制了,附上题目连接:https://vjudge.net/problem/UVA-208
这道题对于学过经典暴搜算法DFS和BFS的同学来讲思路非常简单,也非常好写,思路就是DFS暴力搜索不过考虑到字典序问题所以可以提前排序。于是我们就写出了这样的代码:提交上去却显示TLE。。

import java.util.*;
import java.math.*;
import java.lang.*;
public class Main{
    public static int [][]firestreet = new int[30][30];
    public static int []way = new int[30];
    public static boolean []visit = new boolean[30];
    public static int cnt;
    public static void DFS(int cur,int root,int n){
        if(cur==n){
            System.out.print("1 ");
            for(int i = 0;i<root;i++){
                System.out.print(way[i]+" ");
            }
            System.out.println();
            cnt++;
            return;
        }
        for(int i = 1;i<=firestreet[cur][0];i++){
            if(!visit[firestreet[cur][i]]){
                visit[firestreet[cur][i]] = true;
                way[root] = firestreet[cur][i];
                DFS(firestreet[cur][i],root+1,n);
                visit[firestreet[cur][i]] = false;
            }
        }
        return;
    }
    public static void main(String[]args){
        Scanner cin = new Scanner(System.in);
        int t = 1;
    while(cin.hasNext()){
        int streetcorner = cin.nextInt();
        Arrays.fill(visit,false);
        for(int i = 1;i<=21;i++)
            Arrays.fill(firestreet[i],0);
        while(true){
            int x = cin.nextInt(),y = cin.nextInt();
            if(x==0&&y==0) break;
            firestreet[x][0]++;
            firestreet[y][0]++;
            firestreet[x][firestreet[x][0]] = y;
            firestreet[y][firestreet[y][0]] = x;
        }
        for(int i = 1;i<=21;i++){
            Arrays.sort(firestreet[i],1,firestreet[i][0]+1);
        }
        cnt = 0;
        visit[1] = true;
        DFS(1,0,streetcorner);
        System.out.printf("CASE %d:",t++);
        System.out.println();
        System.out.printf("There are %d routes from the firestation to streetcorner %d.",cnt,streetcorner);
        System.out.println();
    }
    }
}

一开始我以为是JAVA读写太慢于是改成快读快输疯狂提交,结果却是疯狂TLE。。直到后来我用c++写交也显示TLE的时候我意识到是一开始的思路就有问题,后来看了网上的做法,这道题虽然只有21个消防站但数据会给出无法到达终点站但路径却十分曲折的情况,所以才会出现TLE,所以有一个做法就是先用并查集看1是否可以到终点站再来觉得是否DFS,我改动了一下之前的代码,AC了,代码如下:
JAVA版本(采用了快读,用scanner应该也能AC):

import java.util.*;
import java.math.*;
import java.lang.*;
import java.io.*;
public class Main{
    public static int [][]firestreet = new int[30][30];
    public static int []way = new int[30];
    public static boolean []visit = new boolean[30];
    public static int []father = new int[30];
    public static int cnt;
    public static int myfind(int x){
        int r = x;
        while(father[r]!=r)
            r = father[r];
        int i = x,j;
        while(i!=r){
            j = father[i];
            father[i] = r;
            i = j;
        }
        return r;
    }
    public static void DFS(int cur,int root,int n){
        if(cur==n){
            System.out.print("1 ");
            for(int i = 0;i<root;i++){
                if(i!=root-1)
                    System.out.print(way[i]+" ");
                else
                    System.out.print(way[i]);
            }
            System.out.println();
            cnt++;
            return;
        }
        for(int i = 1;i<=firestreet[cur][0];i++){
            if(!visit[firestreet[cur][i]]){
                visit[firestreet[cur][i]] = true;
                way[root] = firestreet[cur][i];
                DFS(firestreet[cur][i],root+1,n);
                visit[firestreet[cur][i]] = false;
            }
        }
        return;
    }
    public static void main(String[]args)throws IOException{
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        //PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        int t = 1;
    while(in.nextToken() != StreamTokenizer.TT_EOF){
        int streetcorner;
        streetcorner = (int) in.nval;
        for(int i = 0;i<=21;i++){
            father[i] = i;
        }
        for(int i = 1;i<=21;i++)
            Arrays.fill(firestreet[i],0);
        Arrays.fill(visit,false);
        while(true){
            in.nextToken();
            int x = (int) in.nval;
            in.nextToken();
            int y = (int) in.nval;
            if(x==0&&y==0) break;
            father[myfind(x)] = myfind(y);
            firestreet[x][0]++;
            firestreet[y][0]++;
            firestreet[x][firestreet[x][0]] = y;
            firestreet[y][firestreet[y][0]] = x;
        }
        cnt = 0;
        System.out.printf("CASE %d:",t++);
        System.out.println();
        if(myfind(1)==myfind(streetcorner)){
            for(int i = 1;i<=21;i++){
                Arrays.sort(firestreet[i],1,firestreet[i][0]+1);
            }
            visit[1] = true;
            DFS(1,0,streetcorner);
        }
        System.out.printf("There are %d routes from the firestation to streetcorner %d.",cnt,streetcorner);
        System.out.println();
    }
    }
}

C++11版本

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
int firestreet[30][30],way[30],pre[30],cnt;
bool visit[30];
int myfind(int x){
    int r = x;
    while(pre[r]!=r)
        r = pre[r];
    int i = x,j;
    while(i!=r){
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}

void DFS(int cur,int root,int n){
    if(cur==n){
            printf("1 ");
            for(int i = 0;i<root;i++){
                if(i!=root-1)
                    printf("%d ",way[i]);
                else
                    printf("%d",way[i]);
            }
            printf("\n");
            cnt++;
            return;
        }
        for(int i = 1;i<=firestreet[cur][0];i++){
            if(!visit[firestreet[cur][i]]){
                visit[firestreet[cur][i]] = true;
                way[root] = firestreet[cur][i];
                DFS(firestreet[cur][i],root+1,n);
                visit[firestreet[cur][i]] = false;
            }
        }
        return;
}
int main()
{
    //freopen("text.txt","r",stdin);
    int t = 1,streetcorner;
    while(cin>>streetcorner){
        memset(firestreet,0,sizeof(firestreet));
        memset(visit,false,sizeof(visit));
        for(int i = 0;i<=21;i++){
            pre[i] = i;
        }
        while(true){
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==0||y==0) break;
            pre[myfind(x)] = myfind(y);
            firestreet[x][0]++;
            firestreet[y][0]++;
            firestreet[x][firestreet[x][0]] = y;
            firestreet[y][firestreet[y][0]] = x;
        }
        cnt = 0;
        printf("CASE %d:\n",t++);
        if(myfind(1)==myfind(streetcorner)){
            for(int i = 1;i<=21;i++){
                if(firestreet[i][0]!=0){
                    sort(firestreet[i]+1,firestreet[i]+firestreet[i][0]+1);
                }
            }
            visit[1] = true;
            DFS(1,0,streetcorner);
        }
        printf("There are %d routes from the firestation to streetcorner %d.\n",cnt,streetcorner);
    }
    return 0;
}

好了,现在我们再来回顾一下我们的做法:虽然AC了但也是因为数据给的太水,如果出现曲折并且1能到达6的情况同样可能WA,所以最好的办法是采用双向搜索加剪枝的做法。
//容我先休息一下再去写双向搜索加剪枝,写完回来更O(∩_∩)O~~


刚才看一下之前我的代码其实可以进一步优化就是用并查集查询下一节点是否与streetcorner相连,不是就舍去,这样的话就能大大的减少我们的搜索次数。//并查集+DFS还能这样用,学到了。。(__) 嘻嘻……
附上优化代码:(其实就在DFS判断上多了一句话)

import java.util.*;
import java.math.*;
import java.lang.*;
import java.io.*;
public class UVA208{
    public static int [][]firestreet = new int[30][30];
    public static int []way = new int[30];
    public static boolean []visit = new boolean[30];
    public static int []father = new int[30];
    public static int cnt;
    public static int myfind(int x){
        int r = x;
        while(father[r]!=r)
            r = father[r];
        int i = x,j;
        while(i!=r){
            j = father[i];
            father[i] = r;
            i = j;
        }
        return r;
    }
    public static void DFS(int cur,int root,int n){
        if(cur==n){
            System.out.print("1 ");
            for(int i = 0;i<root;i++){
                if(i!=root-1)
                    System.out.print(way[i]+" ");
                else
                    System.out.print(way[i]);
            }
            System.out.println();
            cnt++;
            return;
        }
        for(int i = 1;i<=firestreet[cur][0];i++){
            if(!visit[firestreet[cur][i]]&&myfind(firestreet[cur][i])==myfind(n)){
                visit[firestreet[cur][i]] = true;
                way[root] = firestreet[cur][i];
                DFS(firestreet[cur][i],root+1,n);
                visit[firestreet[cur][i]] = false;
            }
        }
        return;
    }
    public static void main(String[]args)throws IOException{
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        //PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        int t = 1;
    while(in.nextToken() != StreamTokenizer.TT_EOF){
        int streetcorner;
        streetcorner = (int) in.nval;
        for(int i = 0;i<=21;i++){
            father[i] = i;
        }
        for(int i = 1;i<=21;i++)
            Arrays.fill(firestreet[i],0);
        Arrays.fill(visit,false);
        while(true){
            in.nextToken();
            int x = (int) in.nval;
            in.nextToken();
            int y = (int) in.nval;
            if(x==0&&y==0) break;
            father[myfind(x)] = myfind(y);
            firestreet[x][0]++;
            firestreet[y][0]++;
            firestreet[x][firestreet[x][0]] = y;
            firestreet[y][firestreet[y][0]] = x;
        }
        cnt = 0;
        System.out.printf("CASE %d:",t++);
        System.out.println();
        if(myfind(1)==myfind(streetcorner)){
            for(int i = 1;i<=21;i++){
                Arrays.sort(firestreet[i],1,firestreet[i][0]+1);
            }
            visit[1] = true;
            DFS(1,0,streetcorner);
        }
        System.out.printf("There are %d routes from the firestation to streetcorner %d.",cnt,streetcorner);
        System.out.println();
    }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,464评论 25 707
  • 归去来兮。 1.1 说明 本篇为《挑战程序设计竞赛(第2版)》[http://www.ituring.com.cn...
    尤汐Yogy阅读 14,274评论 0 160
  • 深冬就这样悄悄地来了,没有一声招呼,没有一句问候。 而冬天的阳光,在我居住的小城是那样的吝惜,是那样的企不可及。 ...
    秋之语阅读 348评论 24 7
  • 注意点 函数、变量、属性都是对大小写敏感的。 定义用户变量 Jmeter: 鼠标右键,点击添加,选择配置元件,选择...
    一直小鱼阅读 371评论 0 1
  • 曾几何时,我们是自行车王国,因为那是人们唯一能买得起的交通工具;时至今日,拥有汽车早就是家常便饭,也有一句“宁坐宝...
    Thinkpolo阅读 384评论 0 1