1. 程式人生 > 其它 >惡意程式碼 - Malicious Code - BFS & 01揹包

惡意程式碼 - Malicious Code - BFS & 01揹包

惡意程式碼

(測試用例總數:X 個,1 秒 (C/C++),1.5 秒 (JAVA)/記憶體要求:256 M,Stack 1 M)

S 公司的網路管理員琳收到了一通緊急來電。來電告知公司內部裝置連線的網路中發現了惡意程式碼,必須馬上採取相應措施。

S 公司有 N 臺裝置,通過 M 根線路連線,所以如果其中一臺裝置感染惡意程式碼,其他裝置也會通過連線網路感染上惡意程式碼。目前,已有 K 臺裝置感染惡意程式碼,程式碼擴散危機迫在眉睫。受感染的裝置需要立即處理,但在目前的情況下,最多隻能處理三臺裝置

保受感染的裝置數量儘可能少的情況下,幫助琳確定要處理的裝置,同時求出未受感染裝置的最大數量

如上圖所示,有 10 臺裝置連線,編號為 2、4、5、8 的裝置感染了惡意程式碼,處理編號為 2、4、5 的裝置,就可以保護 7 臺裝置,這是能實現的不受感染裝置的最大數量。

[限制條件]

1.裝置數量N為5以上,100,000以下的整數。

2.線路數量 M 為1以上,300,000以下的整數。

3.受感染的裝置數K為3以上,N以下的整數。

4.受感染的裝置即使經過處理後,仍然可能會再次被其他受感染的裝置感染。

[輸入]

首先給出測試用例數量T,隨後給出T個測試用例。在每個測試用例的第一行,給定裝置數量 N,線路數量 M、感染惡意程式碼的裝置數量 K,以空格分隔。從第二行到第M行,每行給定一條線路兩端連線的裝置 A 和 B 的編號,以空格分隔。在第 M+2 行,給定 K 臺感染惡意程式碼的裝置編號,以空格分隔。

[輸出]

每行輸出一個測試用例。首先,輸出“#x”(其中 x 表示測試用例編號,從 1 開始),加一個空格,最後輸出處理三臺裝置後,惡性程式碼擴散時,能實現的未感染裝置的最大數量

[輸入和輸出示例]

(輸入)

2

10 9 4

1 2

2 3

2 5

4 5

4 6

5 6

5 7

8 9

9 10

2 4 5 8

10 9 5

1 2

2 3

2 5

4 5

4 6

5 6

5 7

8 9

9 10

2 4 5 6 8

(輸出)

#1 7

#2 3

思路分析:

bfs遍歷算出每個連通圖中感染病毒的結點數及連通圖總結點數,感染病毒結點數>3 則丟棄,<=3存放在List集合中
根據題意最多可修復的電腦數是3個,可以理解為01揹包中已知最大容量,將感染的電腦看做一個整體的物品,物品權重wi即可修復的電腦數量,物品價值即連通圖節點數
套用01揹包工時dp[j] = max(dp[j-w[i]]+vi,dp[j]),最後算出的dp[3] 則為最後的結果

package graph;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;

/**
 * 惡意程式碼思路分析:
 * bfs+01揹包
 * bfs遍歷算出每個連通圖中感染病毒的結點數及連通圖總結點數,感染病毒結點數>3 則丟棄,<=3存放在List集合中
 * 根據題意最多可修復的電腦數是3個,可以理解為01揹包中已知最大容量,將感染的電腦看做一個整體的物品,物品權重wi即可修復的電腦數量,物品價值即連通圖節點數
 * 套用01揹包工時dp[j] = max(dp[j-w[i]]+vi,dp[j]),最後算出的dp[3] 則為最後的結果
 * 
 * @author XA-GDD
 *
 */
public class EQ_MaliciousCode_0712 {
	static int T,N,M,K;
	static int _max_Nval = 100000;
	static ArrayList<Integer> [] adjList = new ArrayList[_max_Nval+1];
	static boolean [] badNode = new boolean[_max_Nval+1];
	static boolean [] visited = new boolean[_max_Nval+1];
	static ArrayList<int []> list = new ArrayList<int[]>();
	static int [] dp = new int[4];
	static int nodeCnt;
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\sw_pro\\test_case\\sample_input_0712.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	    StringTokenizer st = new StringTokenizer(br.readLine());
		T = Integer.parseInt(st.nextToken());
	    for(int testCase = 1; testCase<= T;testCase++) {
	    	st = new StringTokenizer(br.readLine());
	    	N = Integer.parseInt(st.nextToken());
	    	M = Integer.parseInt(st.nextToken());
	    	K = Integer.parseInt(st.nextToken());
	    	
			for(int i=1;i<=N;i++) {
				adjList[i] = new ArrayList<Integer>();
			}
	    	
			// Arrays.fill(adjList, new ArrayList<Integer>()); 初始化不可用此程式碼
	    	Arrays.fill(badNode, false);
	    	Arrays.fill(visited, false);
	    	list.clear();
	    	Arrays.fill(dp, 0);
	    	nodeCnt = 0;
	    	
	    	for(int i=0;i<M;i++) {
	    		st = new StringTokenizer(br.readLine());
	    		int s = Integer.parseInt(st.nextToken());
	    		int e = Integer.parseInt(st.nextToken());
	    		adjList[s].add(e);
	    		adjList[e].add(s);
	    	}
	    	
	    	st = new StringTokenizer(br.readLine());
	    	for(int i=0;i<K;i++) {
	    		int node = Integer.parseInt(st.nextToken());
	    		badNode[node] = true;
	    	}
	    	
	    	for(int i=1;i<=N;i++) {
	    		if(nodeCnt==N) {
	    			break;
	    		}
	    		if(!visited[i]) {
	    			bfs(i);
	    		}	
	    	}
	    	
	    	getResult();
	    	System.out.printf("#%d %d\n",testCase,dp[3]);
	    }
	}
	
	//0-1揹包
	static void getResult() {
		for(int i=0;i<list.size();i++) {
			int wi = list.get(i)[1];
			int vi = list.get(i)[0];
			for(int j=3;j>=wi;j--) {
				dp[j] = Math.max(dp[j], dp[j-wi]+vi);
			}
		}
	}

	//bfs遍歷算出每個連通圖中感染病毒的結點數及連通圖總結點數,感染病毒結點數>3 則丟棄,<=3存放在List集合中
	static void bfs(int s) {
		Queue<Integer> queue = new ArrayDeque<Integer>();
		queue.add(s);
		visited[s] = true;
		
		int nodeTotCnt = 0; //連通圖的節點個數
		int badNodeCnt = 0; //壞節點個數 
		while(!queue.isEmpty()) {
			int curr = queue.poll();
			nodeTotCnt++;
			nodeCnt++;
			if(badNode[curr]) {
				badNodeCnt++;
			}
			
			for(int i=0;i<adjList[curr].size();i++) {
				int next = adjList[curr].get(i);
				if(!visited[next]) {
					queue.add(next);
					visited[next] = true;
				}
			}
		}
		
		if(badNodeCnt<=3) {
			list.add(new int[] {nodeTotCnt,badNodeCnt});
		}
	}
}