第四次实验报告

7-1 连通分量 (100 分)

无向图 G 有 n 个顶点和 m 条边。求 G 的连通分量的数目。

输入格式:

第1行,2个整数n和m,用空格分隔,分别表示顶点数和边数, 1≤n≤50000, 1≤m≤100000.

第2到m+1行,每行两个整数u和v,用空格分隔,表示顶点u到顶点v有一条边,u和v是顶点编号,1≤u,v≤n.

输出格式:

1行,1个整数,表示所求连通分量的数目。

输入样例:

在这里给出一组输入。例如:

6 5
1 3
1 2
2 3
4 5
5 6

输出样例:

在这里给出相应的输出。例如:

2

思路:

这道题很容易想到是用DFS的算法来遍历图,因为用DFS所遍历的就是一个连通的图,先用vector建图,用visited[]记录某点是否被遍历过,初始化为0,然后循环判断每个点是否visited[i]等于零,若为零,则未被遍历,此时用DFS遍历与它有关的图,记录连通个数的变量加一,把这个图的所有点都标志被遍历过

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
int connect = 0;
vector<int> a[50001]; 
int visited[50001] = { 0 };
void DFS(int j) {
    visited[j] = 1;
    int i;
    for (i = 0; i < a[j].size(); i++) { 
        if (visited[a[j][i]]==0) {
            DFS(a[j][i]);
        }
    }
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, m, x, y, i;
    cin >> n >> m;
    for (i = 0; i < m; i++) {
        cin >> x >> y;
        a[x].push_back(y);
        a[y].push_back(x);//无向图,两个点的a[]中都要有对方
    }
    for (i = 1; i <= n; i++) {
        if (visited[i]==0) {
            DFS(i);
            connect++;
        }
    }
    cout << connect;
    return 0;
}

 

 

7-2 整数拆分 (100 分)

整数拆分是一个古老又有趣的问题。请给出将正整数 n 拆分成 k 个正整数的所有不重复方案。例如,将 5 拆分成 2 个正整数的不重复方案,有如下2组:(1,4)和(2,3)。注意(1,4) 和(4,1)被视为同一方案。每种方案按递增序输出,所有方案按方案递增序输出。

输入格式:

1行,2个整数n和k,用空格分隔, 1≤k≤n≤50.

输出格式:

若干行,每行一个拆分方案,方案中的数用空格分隔。

最后一行,给出不同拆分方案的总数。

输入样例:

在这里给出一组输入。例如:

5 2

输出样例:

在这里给出相应的输出。例如:

1 4
2 3
2

思路:

这道题可以具体化为图,然后使用DFS进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。

 

#include <iostream>
using namespace std;
int a[51];
int count1 = 0;
int n, k;
void DFS(int surplus, int j)
{
	if (surplus == 0 && j != k + 1) {
		return;
	}
	if (surplus == 0 && j == k + 1){
		count1++;
		for (int i = 1; i <= k; ++i){
			cout << a[i];
			if (i != k)
				cout << " ";
			else
				cout << endl;

		}
		return;
	}
	for (int i = a[j - 1]; i <= surplus; ++i){
		a[j] = i;
		DFS(surplus - i, j + 1);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> k;
	for (int i = 1; i <= n; ++i){
		a[1] = i;
		DFS(n - i, 2);
	}
	cout << count1;
}

 

7-3 数字变换 (100 分)

利用变换规则,一个数可以变换成另一个数。变换规则如下:(1)x 变为x+1;(2)x 变为2x;(3)x 变为 x-1。给定两个数x 和 y,至少经过几步变换能让 x 变换成 y.

输入格式:

1行,2个整数x和y,用空格分隔, 1≤x,y≤100000.

输出格式:

第1行,1个整数s,表示变换的最小步数。

第2行,s个数,用空格分隔,表示最少变换时每步变换的结果。规则使用优先级顺序: (1),(2),(3)。

输入样例:

在这里给出一组输入。例如:

2 14

输出样例:

在这里给出相应的输出。例如:

4
3 6 7 14

思路:

这道题也是要用图来做,但不同于前两题的是,这道题是要求最先得出答案的方案而不是得出所有方案,所以这道题应该用BFS而不是DFS

#include <iostream>
#include <queue>
#include <stack>
using namespace std;
int x, y;
int step;
int visited[200001];
int path[200001];
queue<int> q;
stack<int> s;
void BFS(int num){
	q.push(num);
	visited[num] = 1;
	int a;
	while (1){
		a = q.front();
		q.pop();
		if (!visited[a + 1]){
			q.push(a + 1);
			visited[a + 1] = 1;
			path[a + 1] = a;
			if (a + 1 == y) {
				break;
			}
		}
		if (a * 3 <= 2 * y - 1 && !visited[a * 2]){
			q.push(a * 2);
			visited[a * 2] = 1;
			path[a * 2] = a;
			if (a * 2 == y)
				break;
		}
		if (a - 1 > 0 && !visited[a - 1]){
			q.push(a - 1);
			visited[a - 1] = 1;
			path[a - 1] = a;
			if (a - 1 == y)
				break;
		}
	}
	s.push(y);
	while (s.top() != x){
		s.push(path[s.top()]);
		step++;
	}
	cout << step << endl;
	s.pop();
	cout << s.top();
	s.pop();
	while (!s.empty()){
		cout << " " << s.top();
		s.pop();
	}
	cout << endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int i;
	cin >> x >> y;
	if (y == x){
		cout << "0" << endl;
		return 0;
	}
	else if (y < x){
		cout << x - y << endl;
		cout << x - 1;
		for (i = x - 2; i >= y; i--)
			cout << " " << i;
		cout << endl;
		return 0;
	}
	else
		BFS(x);
}

 

7-4 旅行 I (100 分)

五一要到了,来一场说走就走的旅行吧。当然,要关注旅行费用。由于从事计算机专业,你很容易就收集到一些城市之间的交通方式及相关费用。将所有城市编号为1到n,你出发的城市编号是s。你想知道,到其它城市的最小费用分别是多少。如果可能,你想途中多旅行一些城市,在最小费用情况下,到各个城市的途中最多能经过多少城市。

输入格式:

第1行,3个整数n、m、s,用空格分隔,分别表示城市数、交通方式总数、出发城市编号, 1≤s≤n≤10000, 1≤m≤100000 。

第2到m+1行,每行三个整数u、v和w,用空格分隔,表示城市u和城市v的一种双向交通方式费用为w , 1≤w≤10000。

输出格式:

第1行,若干个整数Pi,用空格分隔,Pi表示s能到达的城市i的最小费用,1≤i≤n,按城市号递增顺序。

第2行,若干个整数Ci,Ci表示在最小费用情况下,s到城市i的最多经过的城市数,1≤i≤n,按城市号递增顺序。

输入样例:

在这里给出一组输入。例如:

5 5 1
1 2 2
1 4 5
2 3 4
3 5 7
4 5 8

输出样例:

在这里给出相应的输出。例如:

0 2 6 5 13
0 1 2 1 3

思路:

这道题就是一个用dijkstra算法计算最短路径的题,但是多了一个要求,就是要在最短路径条件下,选择经过的点最多的路

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
#define max 1e5;
int Data[10001];
int cost[10001];
int passnum[10001];
int visited[10001] = { 0 };
vector<pair<int, int> > a[10001];
int n, m, s;
void buildgraph(){
	for (int i = 1; i <= n; i++)
		Data[i] = 1;
	int u, v, w;
	for (int i = 1; i <= m; i++){
		cin >> u >> v >> w;
		a[u].push_back(make_pair(v, w));
		a[v].push_back(make_pair(u, w));
	}
}
void dijk(int s){
	for (int i = 1; i <= n; i++) {
		cost[i] = max;
	}
	cost[s] = 0;
	for (int k = 0; k < n; k++){
		int min = max;
		int border = s;
		for (int i = 1; i <= n; i++) {
			if (cost[i] < min && !visited[i]) {
				min = cost[i];
				border = i;
			}
		}
		visited[border] = 1;
		for (vector<pair<int, int> >::iterator it = a[border].begin(); it != a[border].end(); it++) {
			if (cost[it->first] > min + it->second)
			{
				cost[it->first] = min + it->second;
				passnum[it->first] = passnum[border] + 1;
			}
			else if (cost[it->first] == cost[border] + it->second) {
				if (passnum[it->first] < passnum[border] + 1)
					passnum[it->first] = passnum[border] + 1;
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int s;
	cin >> n >> m >> s;
	buildgraph();
	dijk(s);
	cout << cost[1];
	for (int i = 2; i <= n; i++) {
		cout << " " << cost[i];
	}
	cout << endl << passnum[1];
	for (int i = 2; i <= n; i++) {
		cout << " " << passnum[i];
	}
	cout << endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值