顶点覆盖 Java题解 (模拟)【PAT甲级1134】

58 篇文章 3 订阅
32 篇文章 1 订阅

输入样例:

10 11
8 7
6 8
4 5
8 4
8 1
1 2
1 4
9 8
9 1
1 0
2 4
5
4 0 3 8 4
6 6 1 7 5 4 9
3 1 8 4
2 2 8
7 9 8 7 6 5 4 2

输出样例:

No
Yes
Yes
No
No

解题思路:

要判断所给出的点是否可以覆盖所有边的顶点,可以按这种要求模拟,将每次询问的所有点都遍历它所接壤的边,判断总边数是否被这些顶点都覆盖了,但这种时间复杂度很大,达到O(k·n·n),最坏10^10,直接超时。但是如果反过来考虑,判断所有的边的两点是否在给定的一行询问中都存在,直接遍历边即可,时间复杂度为O(k·n),最坏10^6,不会超时。

在储存边时,因为程序中只是用到到了两边的顶点,并没有要求将边相连,或者遍历边,所以并不需要将边以邻接表存储,可以只用一个类存储所有边的顶点即可。

Java代码:(通过点判断边)超时

import java.io.*;
import java.util.Arrays;

public class Main {
	static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	public static int ini() throws IOException {
		st.nextToken();
		return (int)st.nval;
	}
	
	static int N = 10005, idx;
	static int []e = new int[N];
	static int []ne = new int[N];
	static int []h = new int[N];
	
	public static void main(String[] args) throws IOException {
		int n = ini(), m = ini();
		boolean [][]vis = new boolean[n][n];
		Arrays.fill(h, -1);
		
		int sum = 0;
		while(m-- > 0) {
			int a = ini(), b = ini();
			add(a, b);
			add(b, a);
			sum += 2;
		}
		
		int q = ini();
		while(q-- > 0) {
			int k = ini();
			int res = 0;
			while(k-- > 0) {
				int t = ini(); // 每输入一点,累加它所有相连的边
				for(int i = h[t]; i != -1; i = ne[i]) {
					int j = e[i];
					if(!vis[t][j]) {  // 将还没有标记过的边相加
						vis[t][j] = vis[j][t] = true;
						res += 2;
					}
				}
			}
			if(res == sum) System.out.println("Yes"); // 判断是否与总边数相等
			else System.out.println("No");
			
			for(int i = 0; i < n; i++) Arrays.fill(vis[i], false); // 更新标记数组
		}
		
	}
	
	public static void add(int a, int b) {
		e[idx] = b;
		ne[idx] = h[a];
		h[a] = idx++;
	}
}

Java代码:(通过邻接表的边判断点)AC

import java.io.*;
import java.util.Arrays;

public class Main {
	static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	public static int ini() throws IOException {
		st.nextToken();
		return (int)st.nval;
	}
	
	static int N = 10005, idx;
	static int []e = new int[N];
	static int []ne = new int[N];
	static int []h = new int[N];
	
	public static void main(String[] args) throws IOException {
		int n = ini(), m = ini();
		Arrays.fill(h, -1);
		
		for(int i = 0; i < m; i++) {
			int a = ini(), b = ini();
			add(a, b);
			add(b, a);
		}
		
		int q = ini();
		boolean vis[] = new boolean[n];
		while(q-- > 0) {
			int k = ini();
			Arrays.fill(vis, false);
			for(int i = 0; i < k; i++)  // 将每个询问的点数标记出来 
				vis[ini()] = true;
				
			boolean flag = true;
			for(int i = 0; i < n; i++) {  // 遍历所有边,判断是否任意两边在点集中都至少有一个存在
				for(int t = h[i]; t != -1; t = ne[t]) {
					int j = e[t];
					if(!vis[j] && !vis[i]) {
						flag = false;
						System.out.println("No");
						break;
					}
				}
				if(!flag) break;
			}
			if(flag) System.out.println("Yes");
		}
	}
	
	public static void add(int a, int b) {
		e[idx] = b;
		ne[idx] = h[a];
		h[a] = idx++;
	}
}

Java代码:(通过直接存储边判断点)AC

import java.io.*;
import java.util.Arrays;

public class Main {
	static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	public static int ini() throws IOException {
		st.nextToken();
		return (int)st.nval;
	}
	
	static class Node{
		int a, b;
		public Node(int a, int b) {
			this.a = a;
			this.b = b;
		}
	}
	
	public static void main(String[] args) throws IOException {
		int n = ini(), m = ini();
		Node []node = new Node[m];
		for(int i = 0; i < m; i++) 
			node[i] = new Node(ini(), ini());
		
		int q = ini();
		boolean vis[] = new boolean[n];
		while(q-- > 0) {
			int k = ini();
			
			Arrays.fill(vis, false);
			while(k-- > 0) vis[ini()] = true;
				
			int i = 0;
			for(i = 0; i < m; i++)  // 直接遍历所有边
				if(!vis[node[i].a] && !vis[node[i].b])
					break;
			if(i == m) System.out.println("Yes");
			else System.out.println("No");
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值