L2-1 分而治之(25 分)
這道題時間掐的很緊,非隨機訪問不能被過,二分查詢有待驗證。主要是考慮到 交換也會帶來時間的代價,同時也不能一下子建立 10000*10000的陣列求解,所以想了幾天,一直不想看什麼題解。
L2-1 分而治之(25 分)
分而治之,各個擊破是兵家常用的策略之一。在戰爭中,我們希望首先攻下敵方的部分城市,使其剩餘的城市變成孤立無援,然後再分頭各個擊破。為此參謀部提供了若干打擊方案。本題就請你編寫程式,判斷每個方案的可行性。
輸入格式:
輸入在第一行給出兩個正整數 N 和 M(均不超過10 000),分別為敵方城市個數(於是預設城市從 1 到 N 編號)和連線兩城市的通路條數。隨後 M 行,每行給出一條通路所連線的兩個城市的編號,其間以一個空格分隔。在城市資訊之後給出參謀部的系列方案,即一個正整數 K (≤
Np v[1] v[2] ... v[Np]
其中 Np
是該方案中計劃攻下的城市數量,後面的系列 v[i]
是計劃攻下的城市編號。
輸出格式:
對每一套方案,如果可行就輸出YES
,否則輸出NO
。
輸入樣例:
10 11
8 7
6 8
4 5
8 4
8 1
1 2
1 4
9 8
9 1
1 10
2 4
5
4 10 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
剛開始看到這道題,我的第一個思路就是查和斷,最後找一下。但是是這樣的
map<int,map<int,int> >AT
這樣似乎建立了一個模擬版的 二維陣列,我現在要做的事情 首先是賦值 比如 1 2 之間有聯絡 就AT[1][2]=true;
就這樣我們錄入之後,如樣例所示,是這樣子的
都是 TRUE。然後我們看下面
第一個測試樣例 返回 NO 為什麼返回no呢?我們把這些數字在上圖中,只要含有的區域劃掉,看看
是不是沒有劃完??對!沒有劃完就是NO。我們看看第二個例子
我們劃劃看
劃完了,所以是YES 大體思路就是這樣,可是,硬傷就來了,假定有1W組資料的情況,我要做的是找,劃,再遍歷一次看看有沒有沒有劃掉的。map只能find到 KEY值 VALUE的值無法直接去find ,所以動用迴圈一定會爆炸超時的。想了很多辦法,比如三容器+find法都報了超時。難道這就無解了嗎。我們看一下我超時的程式碼:
#include <bits/stdc++.h>
using namespace std;
vector<int>AS1;
vector<int>AS2;
vector<bool>AS3;
int betafind(vector<int>ADT, vector<bool>AS3, int pd) {
int cnt = 0;
for (int i = 0; i < ADT.size(); i++) {
for (vector<int>::iterator it = AS1.begin(); it = find(it, AS1.end(), ADT[i]), it != AS1.end(); it++) {
if (AS3[it - AS1.begin()])
AS3[it - AS1.begin()] = false, cnt++;
}
for (vector<int>::iterator it = AS2.begin(); it = find(it, AS2.end(), ADT[i]), it != AS2.end(); it++) {
if (AS3[it - AS2.begin()])
AS3[it - AS2.begin()] = false, cnt++;
}
}
return pd == cnt ? 1 : 0;
}
void betasolve() {
int lu, gx;
cin >> lu >> gx;
for (int i = 0; i < gx; i++) {
int t, p;
cin >> t >> p;
AS1.push_back(t);
AS2.push_back(p);
AS3.push_back(true);
}
int ts;
cin >> ts;
for (int ii = ts; ii--;) {
int c;
cin >> c;
vector<int>TST;
for (int sn = c; sn--;) {
int gg;
cin >> gg;
TST.push_back(gg);
}
if (betafind(TST, AS3, gx))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
int main() {
betasolve();
return 0;
}
額,真的不是 cin>> 和 cout << 拖的時間。我自以為用 find會縮短一些時間,再通過指標計算出位置,再用 第三個bool的容器去修改會加快速度。不對!感覺容器的find超級的雞肋。還不如你直接去for ,專門騙我這些小白去用這些東西。
果然,我自以為好的程式碼,報了兩個超時,心情很壞.因此幾天飯吃不好,覺睡不好。我甚至還有以下思路,但是還沒有去實現:
(一下每一點都代表個獨立的思路,不是 過程)
1.用生成樹來找,先把關係通過一定的條件連線然後把要刪除的節點的值設定為-1,然後從頭到尾遍歷,去訪問各個節點,然後每訪問一個節點之前都去檢查當前節點是不是-1,是的話就把計數器給我加一下,最後來幾個判斷。
2.把要刪除的節點從原來的關係之中更改為-1,然後,把它們連線起來,只要每一個節點均指向-1那個節點,那麼說明節點斷開,最後再來一個判斷。
3.使用一個布林型別的標記陣列存下我待刪除的 節點位置所在的區域BOOL值為 false ,然後把點一一給我代入,來一個判斷,如果 vis[原資料1]==true&&vis[原資料2]==true 那麼就證明沒有斷,否則就是斷了 因為關係裡 不會有 這樣的資料 1 2 又來個 2 1 感覺這樣也沒什麼卵用。
然後想了一下,然後,在群裡問了,她說遍歷一遍就行了,讓我有了對第三種方法起了好感。好 第三種 就這樣完成了,我最後還在考慮能不能用 map<bool>去替換那個該死的 1W的陣列,想想 算了 ,畢竟 memset擺在那裡呢!你能對map用memset嗎?這簡直就是瞎扯。
好 看下程式碼,比較簡單,修正了部分地方,使得程式碼AC了 【真的好那麼,學長竟然說那麼肉麻的話給某位女生。算了,畢竟我是不想結婚的人,單身很好,可以提升生活水平,傷心的時候世界把我忘了反而會讓別人開心呢!】
#include <bits/stdc++.h>
using namespace std;
bool text[10000+2];
int tx, px;
void solve() {
pair<int, int>P[10000 + 2];
scanf("%d%d",&tx,&px);
for (int i = 0; i<px;i++) {
int x, y;
scanf("%d%d", &x, &y);
P[i] = { x,y };
}
int tcx;
scanf("%d",&tcx);
for (int i = tcx; i--;) {
int apx;
scanf("%d", &apx);
memset(text, 1, sizeof(text));
for (int j = apx; j--;) {
int xc;
scanf("%d",&xc);
text[xc] = 0;
}
bool tecc;
for (int n = 0; n < px; n++) {
if (text[P[n].first] && text[P[n].second])
tecc = false, n = px;
else
tecc = true;
}
if (tecc)
printf("YES\n");
else
printf("NO\n");
}
}
int main() {
solve();
// system("pause");
return 0;
}