惡意程式碼 - 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}); } } }