圖及其他

1、連通性

給定一個方陣,定義連通:上下左右相鄰,並且值相同。

可以想象成一張地圖,不同的區域被塗以不同顏色。
輸入:
整數N, (N<50)表示矩陣的行列數
接下來N行,每行N個字符,代表方陣中的元素
接下來一個整數M,(M<1000)表示詢問數
接下來M行,每行代表一個詢問,
格式爲4個整數,y1,x1,y2,x2,
表示(第y1行,第x1列) 與 (第y2行,第x2列) 是否連通。
連通輸出true,否則false


例如:
10
0010000000
0011100000
0000111110
0001100010
1111010010
0000010010
0000010011
0111111000
0000010000
0000000000
3
0 0 9 9
0 2 6 8
4 4 4 6


程序應該輸出:
false
true
true
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <utility>
using namespace std;
typedef pair<int, int> loc;
int visit[51][51];
int f(char (*aa)[51], loc a, loc b, int c){
	if(a.first == b.first && a.second == b.second){
		return 1;
	}
	int dy[] = {0, 0, 1, -1};
	int dx[] = {1, -1, 0, 0};
	for(int i = 0; i < 4; i++){
		int ey = a.first + dy[i];
		int ex = a.second + dx[i];
		if(ex >= 0 && ex < c && ey >= 0 && ey < c
		&& visit[ey][ex] == 0 && aa[ey][ex] == aa[a.first][a.second]){
			visit[ey][ex] = 1;
			loc g(ey, ex);
			if(f(aa, g, b, c)){
				return 1;
			}
		}
	}
	return 0;
}
int main(){	
	freopen("input.txt", "r", stdin);
	char a[51][51];
	int b;
//	cin >> b;
	cout << b << endl;
	for(int i = 0; i < b; i++){
		cin >> a[i];
	}
//	for(int i = 0; i < b; i++){
//		for(int j = 0; j < b; j++){
//			cout << a[i][j] << " ";
//		}
//		cout << endl;
//	}
	int c;
	cin >> c;
//	cout << c << endl;
	loc d[2002];
	for(int i = 0; i < 2 * c; i++){
		cin >> d[i].first >> d[i].second;
//		cout << d[i].first << d[i].second << endl;
	}
	
	
	for(int i = 0; i < 2 * c; i += 2){
		for(int j = 0; j < 51; j++){
			for(int k = 0; k < 51; k++){
				visit[j][k] = 0;
			}
		}
		if(f(a, d[i], d[i + 1], b) == 1){
			cout << "true" << endl;			
		}
		else{
			cout << "false" << endl;	
		}
	} 
}

#include <iostream>
#include <cstdio>
#include <cstring>
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int f(char map[][54], int len, int y1, int x1, int y2, int x2){
	if(y1 == y2 && x1 == x2){
		return 1;
	}
	for(int i = 0; i < 4; i++){
		int y3 = y1 + dy[i];
		int x3 = x1 + dx[i];
		char old;
		old = map[y1][x1];
		if(y3 >= 0 && y3 < len 
		&& x3 >= 0 && x3 < len){
			map[y1][x1] = '*';
			if(map[y3][x3] == old && f(map, len, y3, x3, y2, x2)){
				map[y1][x1] = old;
				return 1;
			}
		}
		map[y1][x1] = old;
	}
	return 0;
}
int main(){
	FILE * in;
	FILE * out;
	in = fopen("in.txt", "r");
	out = fopen("out.txt", "w");
	char m1[4];
	int m2; // 矩陣邊長 
	fgets(m1, 4, in);
	sscanf(m1, "%d", &m2);
	fprintf(out, "%d\n", m2);
	char map[54][54];
	for(int i = 0; i < m2; i++){
		fgets(map[i], m2 + 2, in);
	}
	for(int i = 0; i < m2; i++){
		fprintf(out, "%s", map[i]);
	}
	char n1[7];
	int n2;
	fgets(n1, 5, in);
	sscanf(n1, "%d", &n2);
	char test[1002][4];
	char test2[10];
	fprintf(out, "%d\n", n2);
	for(int i = 0; i < n2; i++){
		fgets(test2, 10, in);
		sscanf(test2, "%d %d %d %d", &test[i][0], &test[i][1], &test[i][2], &test[i][3]);
		fprintf(out, "%d %d %d %d\n", test[i][0], test[i][1], test[i][2], test[i][3]);
		int re = f(map, m2, test[i][0], test[i][1], test[i][2], test[i][3]);
		fprintf(out, "%s\n", re == 1 ? "true": "false");
	}
}


2、迷宮問題

...11111111111111111111111111111
11.111111........1111111111.1111
11.111111..111.11111111.....1111
11.11111111111.1111111111.111111
11.111111.................111111
11.111111.11111111111.11111.1111
11.111111.11111111111.11111..111
11.................11.11111.1111
11111.111111111111.11.11....1111
11111.111111111111.11.11.11.1111
11111.111111111111.11.11.11.1111
111...111111111111.11.11.11.1111
111.11111111111111.11....11.1111
111.11111111111111.11111111.1111
111.1111.111111111.11111......11
111.1111.......111.11111.1111.11
111.1111.11111.111.11111.1111.11
111......11111.111.11111.1111111
11111111111111.111.11111.111...1
11111111111111...............1.1
111111111111111111111111111111..

如上圖的迷宮,入口,出口分別:左上角,右下角
"1"是牆壁,"."是通路

求最短需要走多少步?

#include <iostream>
#include <utility>
#include <vector>
using namespace std;
typedef pair<int, int> loc;
vector<loc> v;
void show(){
	for(int i = 0; i < v.size(); i++){
		loc a = v.at(i);
		cout <<"(" << a.first <<","<< a.second <<")";
	}
	cout << endl << endl;
}
int visit[22][35];
int f(char (*aa)[33], loc a){
	visit[0][0] = 1;
	int dx[] = {0, 0, 1, -1};
	int dy[] = {1, -1, 0, 0};
	v.push_back(a);
	int n = 0;
	while(!v.empty()){
//		show();
		loc c = v.front();
		v.erase(v.begin());
//		cout <<"erase";
//		show();
		n = 0;
		int ex, ey;
		for(int i = 0; i < 4; i++){
			ex = c.second + dx[i];
			ey = c.first + dy[i];

			if(ey >= 0 && ey < 22 && ex >= 0 && ex < 32
			&& aa[ey][ex] == '.' && visit[ey][ex] == 0){
				n++;
				visit[ey][ex] = visit[c.first][c.second] + 1;
				loc h(ey, ex);
				v.push_back(h);
			}
		}
	}
	return visit[20][31]; 
}
int main(){
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	char a[22][33];
	for(int i = 0; i < 21; i++){
		cin >> a[i];
	}
	for(int i = 0; i < 21; i++){
		cout << a[i] << endl;
	}
	cout << f(a, loc(0, 0)) << endl;
//	for(int i = 0; i < 22; i++){
//		for(int j = 0; j < 32; j++){
//			printf("%3d", visit[i][j]);
//		}
//		cout << endl;
//	}
}

3、分酒問題

有4個紅酒瓶子,它們的容量分別是:9升, 7升, 4升, 2升  
開始的狀態是 [9,0,0,0],也就是說:第一個瓶子滿着,其它的都空着。


允許把酒從一個瓶子倒入另一個瓶子,但只能把一個瓶子倒滿或把一個瓶子倒空,不能有中間狀態。
這樣的一次倒酒動作稱爲1次操作。


假設瓶子的容量和初始狀態不變,對於給定的目標狀態,至少需要多少次操作才能實現?
本題就是要求你編程實現最小操作次數的計算。
 
輸入:最終狀態(空格分隔)
輸出:最小操作次數(如無法實現,則輸出-1)


例如:
輸入:
9 0 0 0
應該輸出:
0


輸入:
6 0 0 3
應該輸出:
-1


輸入:
7 2 0 0
應該輸出:
2

#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<int> vv;
vector<string> v;
int f1(string a){
	int b[] = {9, 7, 4, 2};
	int c[4];
	for(int i = 0; i < 4; i++){
		c[i] = a.at(i) - '0';
	}
	int d = 0;
	int e = 0;
	for(int i = 0; i < 4; i++){
		d += c[i];
		if(c[i] > b[i]){
			e = 1;
		}
	}
	if(d > 9 || e == 1){
		return 0;
	}
	else{
		return 1;
	}
}
int f(string h, string b){
	string a = h;
	v.push_back(a);
	vv.push_back(0);
	int d[4];
	int aa;
	int e[4] = {9, 7, 4, 2};
	cout << f1(b);
	if(f1(b) == 0){
		return -1;
	}
	while (!v.empty()){
		a = v.front();
//		cout << a << endl;
		v.erase(v.begin());
		aa = vv.front();
		vv.erase(vv.begin());
		if(a == b){
			return aa;
		}
		for (int i = 0; i < 4; i++){
			d[i] = a.at(i) - '0';
		}
		for(int i = 0; i < 4; i++){
			for(int j = 0; j < 4; j++){
				if(i == j)	continue;      //自己 
				if(d[i] == 0)	continue;  //自己爲空 
				if(d[j] == e[j]) continue; //要倒的爲滿 
				int h1, h2;
				h1 = d[i];
				h2 = d[j];
				if(d[i] + d[j] >= e[j]){
					d[i] = d[i] - (e[j] - d[j]);
					d[j] = e[j];
				}
				else{
					d[j] += d[i];
					d[i] = 0;
				}
				a = "";
				for(int i = 0; i < 4; i++){
					a += d[i] + '0';
				}
				v.push_back(a);
				vv.push_back(aa + 1);
				d[i] = h1;
				d[j] = h2;
			}
		}	
	}
	return -1;
}
int main()
{
	string a = "6003";
	cout << f("9000", a);
}

4、風險度量



標題:風險度量


X星系的的防衛體系包含 n 個空間站。這 n 個空間站間有 m 條通信鏈路,構成通信網。
兩個空間站間可能直接通信,也可能通過其它空間站中轉。


對於兩個站點x和y (x != y), 如果能找到一個站點z,使得:
當z被破壞後,x和y不連通,則稱z爲關於x,y的關鍵站點。

顯然,對於給定的兩個站點,關於它們的關鍵點的個數越多,通信風險越大。

你的任務是:已經網絡結構,求兩站點之間的通信風險度,即:它們之間的關鍵點的個數。

輸入數據第一行包含2個整數n(2 <= n <= 1000), m(0 <= m <= 2000),分別代表站點數,鏈路數。
空間站的編號從1到n。通信鏈路用其兩端的站點編號表示。
接下來m行,每行兩個整數 u,v (1 <= u, v <= n; u != v)代表一條鏈路。
最後1行,兩個數u,v,代表被詢問通信風險度的兩個站點。

輸出:一個整數,如果詢問的兩點不連通則輸出-1.


例如:
用戶輸入:
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
則程序應該輸出:
2

資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 2000ms

請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。
所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。
java選手注意:不要使用package語句。不要使用jdk1.7及以上版本的特性。
java選手注意:主類的名字必須是:Main,否則按無效代碼處理。
c/c++選手注意: main函數需要返回0
c/c++選手注意: 只使用ANSI C/ANSI C++ 標準,不要調用依賴於編譯環境或操作系統的特殊函數。
c/c++選手注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

提交程序時,注意選擇所期望的語言類型和編譯器類型。
#include <iostream>
#include <list>
#include <vector>
#include <string>
using namespace std;
void f1(int re[][4], int a, int b){
	if(re[a][3] > b){
		re[a][3] = b;
		f1(re, re[a][1], b);
	}
}
void f(vector<int> * c, int re[][4], int a, int b){
	if(a == b){
		return ;
	}
	for(int i = 0; i < c[a].size(); i++){
		int d = c[a].at(i);
		if(re[d][0] > 0){
			f1(re, a, re[d][2]); //深度傳進去 
			continue;
		}
		re[d][0] = 1;               //訪問標記 
		re[d][1] = a;               //父親結點 
		re[d][2] = re[a][2] + 1;    //深度 
		re[d][3] = re[a][2];        //返祖結點
		f(c, re, d, b);	 
	}
}
int f2(int re[][4], int a, int b){
	int min = re[b][3]; 
	int d = 0;         //sum   
	while(true){
		int c = re[b][1];
//		cout << "father: "  << c << endl;
		if(c == a || c == -1) break;
		if(re[c][2] <= min){
//			cout << "c :" << c << endl;
			d++;	
		}
		if(re[c][3] < min){
			min = re[c][3];
		}
		b = c;
	}
	return d;
}
int main(){
	freopen("input.txt", "r", stdin);
	int a; // 點數 
	int b; //邊數 
	vector<int> c[1002];
	cin >> a >> b;
//	cout << a << " " << b << endl;
	for(int i = 0; i < b; i++){
		int ba, bb;
		cin >> ba >> bb;
//		cout << ba << " " << bb << endl;
		c[ba].push_back(bb);
		c[bb].push_back(ba);
	}
	int ca, cb; //侍求點
	cin >> ca >> cb;
//	cout << ca << " " << cb << endl;
	int re[1002][4]; // (訪問標記,父結點,深度,返祖標記)
	re[ca][0] = 1;
	re[ca][1] = -1;
	re[ca][2] = 1;
	re[ca][3] = -1;
	f(c, re, ca, cb);
	cout << f2(re, ca, cb) << endl;
//	for(int i = 1; i < 7; i++){
//		cout << i  << " :";
//		for(int j = 0; j < 4; j++){
//			cout << re[i][j] << " ";
//		}
//		cout << endl;
//	}
}

5、合根植物

w星球的一個種植園,被分成 m * n 個小格子(東西方向m行,南北方向n列)。每個格子裏種了一株合根植物。
這種植物有個特點,它的根可能會沿着南北或東西方向伸展,從而與另一個格子的植物合成爲一體。
如果我們告訴你哪些小格子間出現了連根現象,你能說出這個園中一共有多少株合根植物嗎?


輸入格式:

第一行,兩個整數m,n,用空格分開,表示格子的行數、列數(1<m,n<1000)。
接下來一行,一個整數k,表示下面還有k行數據(0<k<100000)
接下來k行,第行兩個整數a,b,表示編號爲a的小格子和編號爲b的小格子合根了。
格子的編號一行一行,從上到下,從左到右編號。
比如:5 * 4 的小格子,編號:
1  2  3  4
5  6  7  8
9  10 11 12
13 14 15 16
17 18 19 20

樣例輸入:
5 4
16
2 3
1 5
5 9
4 8
7 8
9 10
10 11
11 12
10 14
12 16
14 18
17 18
15 19
19 20
9 13
13 17
樣例輸出:
5
#include <iostream>
using namespace std;
int ss[1000 * 1000 + 2];
int num = 0;

void unions(int a, int b){
	ss[a] = b;
}
int find(int a){
	int k = a;
	while(ss[k] > 0){
		k = ss[k];
	}
	return k;
}
void f(int a, int b){
//	cout << a << b << endl;
	int c1 = find(a);
	int c2 = find(b);
//	cout << c1 << c2 << endl;
	if(c1 == c2 && c1 != 0){
		return ;
	}
	else{
		unions(c1, c2);
		num++;	
	}
}
int main(){
	freopen("input.txt", "r", stdin);
	int a, b, c;
	cin >> a >> b >> c;
//	cout << a << " " << b  << " " << c << endl;
	int d1, d2;
	for(int i = 0; i < c; i++){
		cin >> d1 >> d2;
//		cout << d1 << " " << d2 << endl;
		f(d1, d2);
	}
//	for(int i = 1; i < a * b; i++){
//		cout << ss[i] << " ";
//		if(i % 5 == 0){
//			cout << endl;
//		}
//	}
//	cout << a * b << endl;
//	cout << num << endl;
	cout << a * b - num;
}

6、最小生成樹(MST) Prim算法

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int f(int n, int len[][102]){
	int dis[102];
	int visit[102];
	memset(visit, 0, 102 * 4);
	visit[1] = 1;
	for (int i = 1; i <= 102; i++){
		dis[i] = len[1][i];
	}	

	int sum = 0;
	for (int k = 2; k <= n; k++){
		int min	= 1 << 30;
		int loc = 0;
		for (int i = 2; i <= n; i++){
			if (min > dis[i] && visit[i] == 0){
				min = dis[i];
				loc = i; 
			}
		}
		visit[loc] = 1;
		cout << "loc" << loc << endl;
		sum += min;
		for(int i = 2; i <= n; i++){
			if(visit[i] == 0 && dis[i] > len[loc][i]){
				dis[i] = len[loc][i];
			}
		}
		for(int i = 1; i <= n; i++){
			cout << dis[i] << " " ;
		}
		cout << endl;	
	}
	return sum;
}
int main(){
	freopen("in.txt", "r", stdin);
	int t;
	int n, m;
	int dis[102][102];
	cin >> t;
	for(int r = 0; r < t; r++){
		cin >> n >> m;
		int total = 0;
		for (int i = 0; i < 102; i++){
			for (int j = 0; j < 102; j++){
				dis[i][j] = (1 << 30);
			}
		}
	
		for (int i = 0; i <= 102; i++){
			dis[i][i] = 0;
		}
		for (int j = 0; j < m; j++){
			int a, b;
			cin >> a >> b;
			cin >> dis[a][b];
			dis[b][a] = dis[a][b];
//			cout << dis[a][b] << endl;
			total += dis[a][b];
		}
//		cout << total << endl;
		cout << total - f(n, dis) << endl;
	}
}

發佈了17 篇原創文章 · 獲贊 3 · 訪問量 9246
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章