2023 算法设计与分析 (计算机与网安)第三次实验课

目录

1. BFS试炼之微博转发

2. DFS试炼之不同路径数

3. 并查集试炼之合并集合

4. 堆排序

5. 厦大GPA

6. 消防安全指挥问题

7. 铺设光纤问题

8. CCF A会报告

9. 商店 (挑战题)


1. BFS试炼之微博转发

Tag:bfs

存储:邻接表

思路:有搜索层数限制,用dist数组记录层数,超出要求则continue

#include
#include
#include
#include
#include
using namespace std;

const int N = 1005;
int n, l;
int e[N], ne[N], h[N], idx, dist[N];
bool st[N];
queue q;

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

int bfs(int x) {
	memset(st, 0, sizeof st);
	memset(dist, 0, sizeof dist);

	q.push(x);
	st[x] = true;

	int cnt = 0;

	while (q.size()) {
		auto t = q.front();
		q.pop();

		for (int i = h[t]; i != -1; i = ne[i]) {
			int j = e[i]; //cout << j << endl;
			if (st[j]) continue;
		
			dist[j] = dist[t] + 1;
			if (dist[j] > l)  continue;

			++ cnt;
			q.push(j);
			st[j] = true;
		}
	}
	return cnt;
}

int main() {

	memset(h, -1, sizeof h);

	cin >> n >> l;
	for (int i = 1; i <= n; ++ i) {
		int num, x;
		cin >> num;
		for (int j = 0; j < num; ++ j) {
			cin >> x;
			add(x, i);
			//	cout << x << ' ' << i << endl;
		}
	}


	int t;
	cin >> t;
	while (t --) {
		int x;
		cin >> x;
		cout << bfs(x) << endl;
	}

	return 0;
}

2. DFS试炼之不同路径数

Tag:dfs,字符串哈希

思路:以每个点为起点dfs搜索。用字符串哈希记录不重复路径数。

#include
#include
#include
#include
#include
using namespace std;

const int N = 7;
char g[N][N];
bool st[N][N];
int n, m, k, ans;
unordered_set s;
char str[10];

void dfs(int x, int y, int u) {

	if (u > k) {
		//cout << str << endl;
		if (!s.count(str)) {
			s.insert(str);
			++ ans;
		}
		return;
	}

	st[x][y] = true;
	str[u] = g[x][y];
	//cout << u << ' ' << str << endl;
	
	int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

	for (int i = 0; i < 4; ++ i) {
		int xx = x + dx[i], yy = y + dy[i];
		if (xx < 0 || xx >= n || yy < 0 || yy >= m) continue;
		dfs(xx, yy, u + 1);
	}
}

int main() {

	cin >> n >> m >> k;

	for (int i = 0; i < n; ++ i)
		for (int j = 0; j < m; ++ j)
			cin >> g[i][j];

	for (int i = 0; i < n; ++ i) {
		for (int j = 0; j < m; ++ j) {
			memset(st, 0, sizeof st);
			dfs(i, j, 0);
		}
	}

	cout << ans << endl;

	return 0;
}

3. 并查集试炼之合并集合

Tag: 并查集

思路:模板题

#include
#include
#include
#include
using namespace std;

const int N = 1e5 + 5;
int p[N];
int n, m;

int find(int x) {
	return x == p[x] ? x : p[x] = find(p[x]);
}

int main() {

	cin >> n >> m;

	for (int i = 1; i <= n; ++ i) p[i] = i;


	while (m --) {
		char c;
		int x, y;
		cin >> c >> x >> y;

		if (c == 'M') {
			if (find(x) != find(y)) p[find(x)] = find(y);
		} else {
			if (find(x) == find(y)) puts("Yes");
			else puts("No");
		}
	}
	
	return 0;
}

4. 堆排序

略。用sort混过去了。

5. 厦大GPA

Tag:分组背包、(贪心)

思路:

        绩点是价值,分数是体积,总分是容积。

        分组背包问题,4组,每组可以取一个分数。

        (前置处理写麻烦了,贪心只用每个档的最低分数数据就可以了)

#include
#include
#include
#include
using namespace std;

//绩点是价值 分数是体积 总分是容积
//分组背包问题 4组 每组可以取一个分数

const int N = 405;
int v[N], w[N];
int f[N];

void init() {
	for (int i = 1, s = 0; s <= 100;) {
		switch (s) {
			case 0:
				for (; s <= 59; ++i, ++s) v[i] = s, w[i] = 0;
				break;
			case 60:
				for (; s <= 63; ++i, ++s) v[i] = s, w[i] = 10;
				break;
			case 64:
				for (; s <= 67; ++i, ++s) v[i] = s, w[i] = 17;
				break;
			case 68:
				for (; s <= 71; ++i, ++s) v[i] = s, w[i] = 20;
				break;
			case 72:
				for (; s <= 74; ++i, ++s) v[i] = s, w[i] = 23;
				break;
			case 75:
				for (; s <= 77; ++i, ++s) v[i] = s, w[i] = 27;
				break;
			case 78:
				for (; s <= 80; ++i, ++s) v[i] = s, w[i] = 30;
				break;
			case 81:
				for (; s <= 84; ++i, ++s) v[i] = s, w[i] = 33;
				break;
			case 85:
				for (; s <= 89; ++i, ++s) v[i] = s, w[i] = 37;
				break;
			case 90:
				for (; s <= 100; ++i, ++s) v[i] = s, w[i] = 40;
				break;
		}
	}
}

int main() {

	init();
//for(int i=1; i<=101; ++ i) printf("%d %d\n", v[i], w[i]);

	int m;
	while (cin >> m) {
		
		memset(f, 0, sizeof f);
		
		for (int i = 1; i <= 4; ++ i) {
			for (int j = m; j >= 0; -- j) {
				for (int k = 1; k <= 101; ++ k)
					if (v[k] <= j)
						f[j] = max(f[j], f[j - v[k]] + w[k]);
				//cout << f[i][j] << endl;
			}
		}
	
		double res = f[m] / 10.0;
		//cout << res << endl;
		printf("%.1f\n", res);
	}

	return 0;
}

 

6. 消防安全指挥问题

Tag:dijkstra

思路:对消防队在的位置为起点dijkstra,比较取最短。

#include
#include
#include
#include
using namespace std;

const int N = 1005;
int xfd[N];
int n, m, p, q;
int g[N][N], dist[N];
bool st[N];

int dijkstra(int x) {
	memset(dist, 0x3f, sizeof dist);
	memset(st, 0, sizeof st);

	dist[x] = 0;

//cout << m << endl;
	for (int i = 0; i < m; ++ i) {
		int t = -1, dis = 0x3f3f3f3f;
		for (int j = 1; j <= m; ++ j) {
			if (!st[j] && (t == -1 || dist[j] < dis)) {
				t = j;
				dis = dist[j];
			}
		}
//cout << t << endl;
	
		st[t] = true;  
		if (t == q) return dist[q];

		for (int i = 1; i <= m; ++ i) dist[i] = min(dist[i], dist[t] + g[t][i]);
		
	}
	return 0x3f3f3f3f;
}

int main() {

	int t;
	cin >> t;

	while (t --) {
		cin >> n >> m >> p >> q; 

		memset(g, 0x3f, sizeof g);

		for (int i = 0; i < n; ++i) cin >> xfd[i];
		while (p --) {
			int a, b, w;
			cin >> a >> b >> w;
			g[a][b] = g[b][a]= min(g[a][b], w);
		}
		
		int ans = 0x3f3f3f3f;
		for (int i = 0; i < n; ++ i) {//cout <

 

7. 铺设光纤问题

Tag:prim

思路:模板题。纳入未标记的离现有的一团点距离最近的点。dist存的是到当前这团点的距离。

#include
#include
#include
#include
using namespace std;

const int N = 105;
int g[N][N], dist[N];
int n, ans;
bool st[N];

void prim() {
	memset(dist, 0x3f, sizeof dist);
	dist[1] = 0;
	for (int i = 0; i < n; ++ i) {
		int dis = 0x3f3f3f3f, t;
		for (int j = 1; j <= n; ++ j) {
			if (!st[j] && dist[j] < dis) {
				dis = dist[j];
				t = j;
			}
		}

		st[t] = true;
		ans += dist[t];
		for (int i = 1; i <= n; ++i) dist[i] = min(dist[i], g[t][i]);
	}
}

int main() {

	cin >> n;

	for (int i = 1; i <= n; ++ i)
		for (int j = 1; j <= n; ++ j)
			cin >> g[i][j];

	prim();

	cout << ans << endl;

	return 0;
}

8. CCF A会报告

Tag:多重背包

思路:模板题。除种类体积外,再循环每个品类的个数。注意判是否小于等于容积。

拓展:如果s[]的范围增大,则可以考虑二进制打包优化。

#include
#include
#include
#include
using namespace std;

const int N = 6005;
int v[N], w[N], s[N];
int n, m;
int f[N];

int main() {

	cin >> n >> m;

	for (int i = 1; i <= n; ++ i) {
		cin >> v[i] >> w[i] >> s[i];
	}

	for (int i = 1; i <= n; ++ i) {
		for (int j = m; j >= v[i]; -- j) {
			for (int k = 1; k <= s[i]; ++ k) {
				if (k * v[i] <= j)
					f[j] = max(f[j], f[j - k * v[i]] + k * w[i]);
			}
		}
	}

	cout << f[m] << endl;

	return 0;
}

9. 商店 (挑战题)

Tag:贪心

存储:优先队列小根堆

思路:
    贪心:为了满足尽可能多的预订单,每次应优先处理商品数少的订单
               又因为当天的货物只可以被当天的订单和后续的订单消耗,所以可以倒序处理数据
    核心:用当前的供应量增序处理队列中的剩余订单

#include
#include
#include
#include
#include
using namespace std;


#define out first
#define index second 
typedef pair PII;
const int N = 3e5 + 5;
priority_queue, greater > q;
int in[N], out[N];
int n, res;

int main() {

	cin >> n;
	for (int i = 1; i <= n; ++ i)  cin >> in[i] >> out[i];

	for(int i=n; i; --i){
		int cur = in[i];
		q.push({out[i], i});
		
		while(q.size()){
			auto t = q.top();
			q.pop();
			
			int csm = min(t.out, cur);
			cur -= csm;
			t.out -= csm;
			
			if(t.out == 0) ++ res;
			else q.push(t);
			
			if(cur == 0) break;
		}
	}
	
	cout << res << endl;
	
	return 0;
}

你可能感兴趣的:(厦大算法设计与分析上机实验,算法,c++,图论,贪心,动态规划)