红色警报 (25 分)【测试点分析】【两种解法】
立志用最少的代碼做最高效的表達(dá)
戰(zhàn)爭(zhēng)中保持各個(gè)城市間的連通性非常重要。本題要求你編寫(xiě)一個(gè)報(bào)警程序,當(dāng)失去一個(gè)城市導(dǎo)致國(guó)家被分裂為多個(gè)無(wú)法連通的區(qū)域時(shí),就發(fā)出紅色警報(bào)。注意:若該國(guó)本來(lái)就不完全連通,是分裂的k個(gè)區(qū)域,而失去一個(gè)城市并不改變其他城市之間的連通性,則不要發(fā)出警報(bào)。
輸入格式:
輸入在第一行給出兩個(gè)整數(shù)N(0 < N ≤ 500)和M(≤ 5000),分別為城市個(gè)數(shù)(于是默認(rèn)城市從0到N-1編號(hào))和連接兩城市的通路條數(shù)。隨后M行,每行給出一條通路所連接的兩個(gè)城市的編號(hào),其間以1個(gè)空格分隔。在城市信息之后給出被攻占的信息,即一個(gè)正整數(shù)K和隨后的K個(gè)被攻占的城市的編號(hào)。
注意:輸入保證給出的被攻占的城市編號(hào)都是合法的且無(wú)重復(fù),但并不保證給出的通路沒(méi)有重復(fù)。
輸出格式:
對(duì)每個(gè)被攻占的城市,如果它會(huì)改變整個(gè)國(guó)家的連通性,則輸出Red Alert: City k is lost!,其中k是該城市的編號(hào);否則只輸出City k is lost.即可。如果該國(guó)失去了最后一個(gè)城市,則增加一行輸出Game Over.。
輸入樣例:
5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3
輸出樣例:
City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.
核心邏輯:若某城市被攻陷,則將其在地圖上刪除,若刪除后的連通塊數(shù)量增加,則該城市為核心城市。
技巧:設(shè)置一個(gè)del數(shù)組,代表該城市是否被攻陷,若是,則不參與計(jì)數(shù)。
解法一:DFS
建立地圖,建立關(guān)聯(lián),每攻陷一個(gè)城市,就深搜一次,判斷連通塊數(shù)量是否增加。
解法二:并查集
建立結(jié)構(gòu)體數(shù)組,存儲(chǔ)所有邊的信息,每攻陷一個(gè)城市,就重新建立一次并查集,判斷連通塊數(shù)量是否增加(注意是重新建立,而不是搜索或查詢)。
特殊樣例
解法一:DFS
#include<iostream> #include<cstdio> #include<cstring> using namespace std;int degree[510]; //每個(gè)節(jié)點(diǎn)的度數(shù) int G[510][510]; //地圖 int vis[510]; //每個(gè)節(jié)點(diǎn)是否出現(xiàn)過(guò) int del[510]; //該節(jié)點(diǎn)是否被刪除,置1表示被刪除 int n, k;void dfs(int step) {for(int i = 0; i < n; i++) if(vis[i] == 0 && del[i]==0 && G[step][i]) {vis[i] = 1;dfs(i);} }int main() {scanf("%d %d", &n, &k);for(int i = 0; i < k; i++) {int x, y;scanf("%d %d", &x, &y);G[x][y] = G[y][x] = 1;} //計(jì)算最初的連通塊數(shù)量 int num_line = 0; //連通塊數(shù)量for(int i = 0; i < n; i++) if(vis[i] == 0) {vis[i] = 1;num_line++;dfs(i); }int m; scanf("%d", &m);for(int i1 = 0; i1 < m; i1++) {int x; scanf("%d", &x);//改進(jìn):直接判斷連通性,若大了,則發(fā)出警告 //刪除與該點(diǎn)有關(guān)的信息 for(int i = 0; i < n; i++) if(G[x][i] == 1) G[x][i] = G[i][x] = 0;del[x] = 1; //初始化vismemset(vis, 0, sizeof(vis)); //判斷連通塊數(shù)量int num_line_after = 0;for(int i = 0; i < n; i++) //如果沒(méi)有遍歷過(guò),并且沒(méi)被刪除過(guò) if(vis[i] == 0 && del[i]==0) {vis[i] = 1;num_line_after++;dfs(i);}//判斷刪除點(diǎn)前后的連通塊數(shù)量是否相同if(num_line < num_line_after) printf("Red Alert: City %d is lost!\n", x);else printf("City %d is lost.\n", x);//更新連通塊的數(shù)量 num_line = num_line_after;if(i1 == n-1) printf("Game Over.\n");}return 0; }耗時(shí):
解法二:并查集
#include<iostream> #include<cstdio> #include<cstring> using namespace std;struct node{int x, y; }edge[5005]; int pre[510]; //存放并查集 int del[510]; //該節(jié)點(diǎn)是否被刪除,置1表示被刪除 int n, k;int find(int x) {return x == pre[x] ? x : pre[x] = find(pre[x]); }void Union(int x, int y) {int fx = find(x);int fy = find(y);if(fx != fy) pre[fx] = fy; // if(fx > fy) pre[fx] = fy; // else pre[fy] = fx; }int main() {scanf("%d %d", &n, &k);for(int i = 0; i < n; i++) pre[i] = i; //并查集初始化 for(int i = 0; i < k; i++) {scanf("%d %d", &edge[i].x, &edge[i].y);Union(edge[i].x, edge[i].y);}int num_line_before = 0; //攻占某城市前連通塊數(shù)量 for(int i = 0; i < n; i++) if(pre[i] == i) num_line_before++;int m; scanf("%d", &m);for(int i1 = 0; i1 < m; i1++) {int x; scanf("%d", &x);del[x] = 1;for(int i = 0; i < n; i++) pre[i] = i;for(int i = 0; i < k; i++) {if(!del[edge[i].x] && !del[edge[i].y]) {Union(edge[i].x, edge[i].y);}}int num_line_after = 0; //攻占某城市后連通塊數(shù)量 for(int i = 0; i < n; i++) if(pre[i] == i && !del[i]) num_line_after++;if(num_line_after > num_line_before) printf("Red Alert: City %d is lost!\n", x);else printf("City %d is lost.\n", x);if(i1 == n-1) printf("Game Over.\n");num_line_before = num_line_after;}return 0; }耗時(shí):
當(dāng)你一無(wú)所有,你就沒(méi)有什么可以失去????????——《泰坦尼克號(hào)》
總結(jié)
以上是生活随笔為你收集整理的红色警报 (25 分)【测试点分析】【两种解法】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux第二章自测习题——Linux系
- 下一篇: 社交网络图中结点的“重要性”计算 (30