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;
}