算法课复习 -- 图、BFS

POJ #2492 : A Bug's Life

传送门:http://poj.org/problem?id=2492

题意:二分图染色。

思路:利用bfs或者dfs遍历即可,没染色的进行染色,染过的判断两点颜色是否一样。

(PE的每个case要空一行)

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<ctime>
#include<functional>
#include<bitset>
#define P pair<int,int>
#define ll long long
#define ull unsigned long long
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ls id*2
#define rs (id*2+1)
#define Mod(a,b) a<b?a:a%b+b
#define cl0(a) memset(a,0,sizeof(a))
#define cl1(a) memset(a,-1,sizeof(a))
using namespace std;

const ll M = 1e9 + 7;
const ll INF = 1e18 + 10;
const double _e = 10e-6;
const int maxn = 2010;
const int matSize = 9;
const int dx[4] = { 0,0,1,-1 }, dy[4] = { 1,-1,0,0 };
const int _dx[8] = { -1,-1,-1,0,0,1,1,1 }, _dy[8] = { -1,0,1,-1,1,-1,0,1 };

int x, y, z;
char c;

int t, n, m;
vector<int> G[maxn];
int used[maxn];

bool bfs()
{
	queue<int> que; 
	for (int i = 1; i <= n; i++) {
		if (used[i] == -1) {
			que.push(i); used[i] = 0;
			while (!que.empty()) {
				int u = que.front(); que.pop();
				for (int j = 0; j < G[u].size(); j++) {
					int v = G[u][j];
					if (used[v] == -1) {
						used[v] = (used[u] + 1) % 2;
						que.push(v);
					}
					else if (used[v] == used[u])
						return false;
				}
			}
		}
	}
	return true;
}

int main()
{
	scanf("%d", &t);
	for (int _ = 1; _ <= t; _++) {
		scanf("%d%d", &n, &m);
		for (int i = 0; i <= 2000; i++)
			G[i].clear();
		cl1(used);
		while (m--) {
			scanf("%d%d", &x, &y);
			G[x].push_back(y);
			G[y].push_back(x);
		}		
		printf("Scenario #%d:\n", _);
		if (bfs())
			puts("No suspicious bugs found!");
		else
			puts("Suspicious bugs found!");
		printf("\n");
	}
	return 0;
}

 

POJ #2631 : Roads in the North

传送门:http://poj.org/problem?id=2631

题意:树上最远距离。

思路:先任取一点,求出到这点距离最远的点a,再求出点a到其他点的最远距离就是答案。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<ctime>
#include<functional>
#include<bitset>
#define P pair<int,int>
#define ll long long
#define ull unsigned long long
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ls id*2
#define rs (id*2+1)
#define Mod(a,b) a<b?a:a%b+b
#define cl0(a) memset(a,0,sizeof(a))
#define cl1(a) memset(a,-1,sizeof(a))
using namespace std;

const ll M = 1e9 + 7;
const ll INF = 1e9;
const int N = 410;
const double _e = 10e-6;
const int maxn = 10010;
const int matSize = 9;
const int dx[4] = { 0,0,1,-1 }, dy[4] = { 1,-1,0,0 };
const int _dx[8] = { -1,-1,-1,0,0,1,1,1 }, _dy[8] = { -1,0,1,-1,1,-1,0,1 };

int x, y, c;
int ans, ansid;
bool used[maxn];

struct node
{
	int id;
	int cost;
};

vector<node> G[maxn];

struct cmp
{
	bool operator()(node a, node b)
	{
		return a.cost > b.cost;
	}
};

void bfs(int u)
{
	used[u] = true;
	priority_queue<node, vector<node>, cmp> que;
	que.push(node{ u,0 });
	while (!que.empty()) {
		int u = que.top().id, d = que.top().cost; que.pop();
		ansid = u; ans = d;
		for (int i = 0; i < G[u].size(); i++) {
			node v = G[u][i];
			if (!used[v.id]) {
				used[v.id] = true;
				que.push(node{ v.id,d + v.cost });
			}
		}
	}
}

int main()
{
	while (~scanf("%d%d%d", &x, &y, &c)) {
		//if (x == 0)break;
		G[x].push_back(node{ y,c });
		G[y].push_back(node{ x,c });
	}
	cl0(used);
	bfs(1);
	cl0(used);
	bfs(ansid);
	printf("%d\n", ans);
	return 0;
}

 

UVA #11080 : Place the Guards

传送门:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2021

题意:有n个路口,m条路,国王准备在某些路口安排一些人来把守。在一个路口把守的人能够把守与他所在的路口相连的所有路。问每条路都有且仅有一人把守,最少需要多少人。若无法满足则输出-1。

思路:将路口分为有人把守(路口0)的和没人把守的(路口1)。

对于所有路口来说,路口0必定与路口1相邻(不然就会有多人把守一条路或者压根没人把守某条路了)。

因此转化为二分图染色问题了。对于每块连通图都进行二分染色,然后取需要染色次数少的那种颜色,相加即为答案。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<ctime>
#include<functional>
#include<bitset>
#define P pair<int,int>
#define ll long long
#define ull unsigned long long
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ls id*2
#define rs (id*2+1)
#define Mod(a,b) a<b?a:a%b+b
#define cl0(a) memset(a,0,sizeof(a))
#define cl1(a) memset(a,-1,sizeof(a))
using namespace std;

const ll M = 1e9 + 7;
const ll INF = 1e18 + 10;
const double _e = 10e-6;
const int maxn = 210;
const int matSize = 9;
const int dx[4] = { 0,0,1,-1 }, dy[4] = { 1,-1,0,0 };
const int _dx[8] = { -1,-1,-1,0,0,1,1,1 }, _dy[8] = { -1,0,1,-1,1,-1,0,1 };

int x, y, z;
char c;

int t, n, m;
vector<int> G[maxn];
int used[maxn];

int bfs()
{
	queue<int> que; int ans = 0;
	for (int i = 0; i < n; i++) {
		if (used[i] == -1) {
			int ans0 = 0, ans1 = 0;
			que.push(i); used[i] = 0; ans0++;
			while (!que.empty()) {
				int u = que.front(); que.pop();
				for (int j = 0; j < G[u].size(); j++) {
					int v = G[u][j];
					if (used[v] == -1) {
						used[v] = (used[u] + 1) % 2;
						if (used[v] == 0)ans0++;
						else ans1++;
						que.push(v);
					}
					else if (used[v] == used[u])
						return -1;
				}
			}
			if (ans0 == 0 || ans1 == 0)
				ans += max(ans0, ans1);
			else
				ans += min(ans0, ans1);
		}
	}
	return ans;
}

int main()
{
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		for (int i = 0; i <= 200; i++)
			G[i].clear();
		cl1(used);
		while (m--) {
			scanf("%d%d", &x, &y);
			G[x].push_back(y);
			G[y].push_back(x);
		}
		int ans = bfs();
		printf("%d\n", ans);
	}
	return 0;
}

 

HDU #1372 : Knight Moves

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1372

题意:8*8的棋盘上,走马步从一个点到另一点的最短距离。

思路:利用bfs预处理所有点间的最短距离即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<ctime>
#include<functional>
#include<bitset>
#define P pair<int,int>
#define ll long long
#define ull unsigned long long
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ls id*2
#define rs (id*2+1)
#define Mod(a,b) a<b?a:a%b+b
#define cl0(a) memset(a,0,sizeof(a))
#define cl1(a) memset(a,-1,sizeof(a))
using namespace std;

const ll M = 1e9 + 7;
const ll INF = 1e9;
const int N = 410;
const double _e = 10e-6;
const int maxn = 10;
const int matSize = 9;
const int dx[4] = { 0,0,1,-1 }, dy[4] = { 1,-1,0,0 };
const int _dx[8] = { -1,-1,-1,0,0,1,1,1 }, _dy[8] = { -1,0,1,-1,1,-1,0,1 };

int xx[8] = { -2,-2,-1,1,1,-1,2,2 };
int yy[8] = { -1,1,2,2,-2,-2,1,-1 };

bool used[maxn][maxn];
int dis[maxn][maxn][maxn][maxn];

struct node
{
	int x, y;
	int d;
};

vector<node> G[maxn];

struct cmp
{
	bool operator()(node a, node b)
	{
		return a.d > b.d;
	}
};

void bfs(int ux, int uy)
{
	used[ux][uy] = true; dis[ux][uy][ux][uy] = 0;
	priority_queue<node, vector<node>, cmp> que;
	que.push(node{ ux,uy,0 });
	while (!que.empty()) {
		node u = que.top(); que.pop();
		for (int i = 0; i < 8; i++) {
			int vx = u.x + xx[i], vy = u.y + yy[i];
			if (vx <= 0 || vx > 8 || vy <= 0 || vy > 8)continue;
			if (!used[vx][vy]) {
				used[vx][vy] = true;
				dis[ux][uy][vx][vy] = u.d + 1;
				que.push(node{ vx,vy,u.d + 1 });
			}
		}
	}
}

int main()
{
	for (int i = 1; i <= 8; i++) {
		for (int j = 1; j <= 8; j++) {
			cl0(used);
			bfs(i, j);
		}
	}
	int x, y;
	char x1, y1;
	while (~scanf("%c%d %c%d", &x1, &x, &y1, &y)) {
		getchar();
		printf("To get from %c%d to %c%d takes %d knight moves.\n", x1, x, y1, y, dis[x1 - 'a' + 1][x][y1 - 'a' + 1][y]);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法导论是计算机科学中非常重要的一门程,它涵盖了计算机算法的设计、分析与应用。期末复习是为了加深对所学知识的理解和掌握,为考试做好充分准备。 使用Python语言进行算法导论的复习是一种很好的选择。Python是一种强大且易于上手的编程语言,具有简洁的语法和丰富的库支持。下面是几个复习的重点: 1. 熟悉Python的基本语法和数据结构:掌握Python的基本数据类型如列表、字典和集合,并了解它们的操作与性能。 2. 掌握常见排序算法复习插入排序、归并排序、快速排序等常见的排序算法,并能够灵活应用它们解决实际问题。 3. 熟悉算法:学习的表示方法,以及广度优先搜索(BFS)和深度优先搜索(DFS)等基本的算法。 4. 熟练应用动态规划算法:了解动态规划的基本思想,复习使用动态规划解决背包问题、最长公共子序列等典型问题。 5. 学习贪心算法:了解贪心算法的概念和特点,熟悉使用贪心算法解决活动选择、哈夫曼编码等问题。 6. 熟练掌握分治算法复习分治算法的基本思想和应用,熟悉使用分治算法解决最大子数组和矩阵乘法等问题。 7. 复习基本的算法分析方法:熟悉时间复杂度和空间复杂度的概念,掌握算法的渐进分析方法。 在复习过程中,可以通过参考教材、堂笔记和习题集等资料进行练习和巩固所学知识。此外,可以参考一些算法导论的相关网上资源和在线教育平台上的程进行深入学习。最重要的是,要坚持刷题,多进行实际编码练习,巩固所学算法的理解和应用能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值