蓝桥杯—网络寻路(JAVA实现,DFS)

一、题目

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。

源地址和目标地址可以相同,但中间节点必须不同。

如下图所示的网络。

1 -> 2 -> 3 -> 1 是允许的

1 -> 2 -> 1 -> 2 或者 1 -> 2 -> 3 -> 2 都是非法的。

输入格式
输入数据的第一行为两个整数N M,分别表示节点个数和连接线路的条数(1<=N<=10000; 0<=M<=100000)。

接下去有M行,每行为两个整数 u 和 v,表示节点u 和 v 联通(1<=u,v<=N , u!=v)。

输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。

输出格式
输出一个整数,表示满足要求的路径条数。
样例输入1
3 3
1 2
2 3
1 3
样例输出1
6
样例输入2
4 4
1 2
2 3
3 1
1 4
样例输出2
10

二、解题思路

我的想法是通过深度优先遍历去找这个点所有有可能的线路,因为题目要求是4个点,所以第四个点有可能是起点,形成一个环,这里我在深度遍历里加了个条件,使得在点数为3的时候进行判断,如果第三个点跟起点有边的话,计数就加一。循环深度遍历所有点,得到最终的计数结果。

三、代码实现

这个代码,得了四十分,后两个超时,最后一个运行错误,我在本地跑了一下,结果是对的。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int n,m,count=0;
	static int [][]arr;
	static int []flag;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		arr=new int[n+1][n+1];
		flag=new int[n+1];
		for(int i=1;i<=m;i++) {
			int u=sc.nextInt();
			int v=sc.nextInt();
			arr[u][v]=arr[v][u]=1;
		}
		for(int i=1;i<=n;i++) {
			DFS(i,i,1);
			Arrays.fill(flag,0);
//			System.out.println("次数为"+i+"时,count为:"+count);
//			System.out.println();
		}
		System.out.println(count);
	}
	private static void DFS(int pot,int st,int bu) {
//		System.out.println("进入点:"+st);
		if(bu==4) {
			count++;
		}
		if(bu>4) {
			return;
		}
//		System.out.println("此时点:"+st+"的count为:"+count);
//		System.out.println("此时步数为:"+bu);
		flag[st]=1;
		for(int i=1;i<=n;i++) {
			if(arr[st][i]==1 && flag[i]==0) {
				DFS(pot,i,bu+1);
				flag[i]=0;
			}
			if(bu==3 && i==n) {//i==n使这个判断条件只会出现一次
				if(arr[st][pot]==1) {
					count++;
				}
			}
		}
		return;
	}
}

大臣的旅费的经验让我萌发了把二维数组改成ArrayList做,还是四十分,但最后一个变成了运行超时,看来ArrayList运行的时间不会缩短多少,只是让内存用少点(自己的感觉)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int n,m,count=0;
	static ArrayList []arr;
	static int []flag;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		arr=new ArrayList[n];
		flag=new int[n+1];
		for(int i=0;i<n;i++) {
			arr[i]=new ArrayList();
		}
		for(int i=0;i<m;i++) {
			int u=sc.nextInt();
			int v=sc.nextInt();
			arr[u-1].add(v-1);
			arr[v-1].add(u-1);
		}
		for(int i=0;i<n;i++) {
			DFS(i,i,1);
			Arrays.fill(flag,0);
//			System.out.println("次数为"+i+"时,count为:"+count);
//			System.out.println();
		}
		System.out.println(count);
	}
	private static void DFS(int pot,int st,int bu) {
//		System.out.println("进入点:"+(st+1));
		if(bu==4) {
			count++;
		}
		if(bu>4) {
			return;
		}
//		System.out.println("此时点:"+(st+1)+"的count为:"+count);
//		System.out.println("此时步数为:"+bu);
		int len=arr[st].size();
		flag[st]=1;
		for(int i=0;i<len;i++) {
			int j=(int) arr[st].get(i);
			if(flag[j]==0) {
				DFS(pot,j,bu+1);
				flag[j]=0;
			}
			if(bu==3 && i==len-1) {
				if(arr[st].contains(pot)) {
					count++;
				}
			}
		}
		return;
	}
}

把scanner输入改为buffer输入,第三个测试点也正确了。接着把深度遍历里的条件调整了一下,去掉过多的遍历。一百分的代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
	static int n,m,count=0;
	static ArrayList<Integer> []arr=new ArrayList[10001];
	static boolean []flag=new boolean[10001];
	public static void main(String[] args) throws IOException {
		BufferedReader bfr = new BufferedReader(
				new InputStreamReader(System.in));
		String c[]=bfr.readLine().split(" ");
		int n = Integer.parseInt(c[0]);
		int m = Integer.parseInt(c[1]);
		int u,v;
		for(int i=0;i<n;i++) {
			arr[i]=new ArrayList();
		}
		for(int i=0;i<m;i++) {
			c=bfr.readLine().split(" ");
			u=Integer.parseInt(c[0]);
			v=Integer.parseInt(c[1]);
			arr[u-1].add(v-1);
			arr[v-1].add(u-1);
		}
		for(int i=0;i<n;i++) {
			DFS(i,i,1);
			Arrays.fill(flag,false);
		}
		System.out.println(count);
	}
	private static void DFS(int pot,int st,int bu) {
		int len=arr[st].size();
		flag[st]=true;
		for(int i=0;i<len;i++) {
			int j=arr[st].get(i);
/*步数为3时,得到的节点如果跟起点相同说明成环,或者得到的节点还没走过就直接加一*/
			if(bu==3 && ((j==pot) || flag[j]==false)) {
				count++;
				continue;//提前结束循环
			}
			if(flag[j]==false) {
				DFS(pot,j,bu+1);
				flag[j]=false;
			}
		}
		return;
	}
}

个人总结

  1. ArrayList比传统二维数组省内存
  2. 使用buffer代替scanner输入,速度明显提升
  3. 注意break和continue语句的灵活运用,可以大大的优化代码速度
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值