1. 程式人生 > >L2-1 分而治之(25 分)

L2-1 分而治之(25 分)

這道題時間掐的很緊,非隨機訪問不能被過,二分查詢有待驗證。主要是考慮到 交換也會帶來時間的代價,同時也不能一下子建立 10000*10000的陣列求解,所以想了幾天,一直不想看什麼題解。

L2-1 分而治之(25 分)

分而治之,各個擊破是兵家常用的策略之一。在戰爭中,我們希望首先攻下敵方的部分城市,使其剩餘的城市變成孤立無援,然後再分頭各個擊破。為此參謀部提供了若干打擊方案。本題就請你編寫程式,判斷每個方案的可行性。

輸入格式:

輸入在第一行給出兩個正整數 N 和 M(均不超過10 000),分別為敵方城市個數(於是預設城市從 1 到 N 編號)和連線兩城市的通路條數。隨後 M 行,每行給出一條通路所連線的兩個城市的編號,其間以一個空格分隔。在城市資訊之後給出參謀部的系列方案,即一個正整數 K (

 100)和隨後的 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;
}