指导老师:Gu Fangming
-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个整数,表示所求连通分量的数目。
代码长度限制
16 KB
时间限制
200 ms
内存限制
10 MB
老师和同学们的思路是用dfs或者bfs遍历来统计根节点个数,也可以运用集合的思想,使用并查集进行运算,统计父亲节点是自身的节点个数即可。
#include <iostream>
#include<stack>
using namespace std;
int father[50010];
int findfathere(int j) {
while (father[j] != j)
j = father[j];
return j;
}
void uni(){
int j, k;
cin >> j >> k;
father[findfathere(k)] = findfathere(j);
}
stack<int> pp;
int main()
{
int n, m,sum=0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
father[i] = i;
for (int i = 1; i <= m; i++)
uni();
for (int t = 1; t <= n; t++) {
int i = t; int z = 0;
while (father[i] != i) {
pp.push(i);
i = father[i];
z++;
}
while (z) {
z--;
father[pp.top()] = i;
pp.pop();
}
}
for (int i = 1; i <= n; i++) {
if (father[i] == i) sum++;
}
cout << sum;
}
-2 整数拆分 (100 分)
整数拆分是一个古老又有趣的问题。请给出将正整数 n 拆分成 k 个正整数的所有不重复方案。例如,将 5 拆分成 2 个正整数的不重复方案,有如下2组:(1,4)和(2,3)。注意(1,4) 和(4,1)被视为同一方案。每种方案按递增序输出,所有方案按方案递增序输出。
输入格式:
1行,2个整数n和k,用空格分隔, 1≤k≤n≤50.
输出格式:
若干行,每行一个拆分方案,方案中的数用空格分隔。
最后一行,给出不同拆分方案的总数。
思想就是走一步看一步(上一个数字确定了,下一个数字可取值的范围也就确定了)
以递归实现就好了,效率还是很高的。
#include <iostream>
using namespace std;
int n, k,sum = 0;
int dd[55]; int top = 1;
void output() {
for (int i = 1; i <= k - 1; i++)
cout << dd[i] << " ";
cout << dd[k] << "\n";
}
void ddd(int deep,int max,int remain) {
int t = remain / (k - deep + 1);
if(deep!=k)
for (int i = max; i <= t; i++) {
dd[top] = i;
top++;
ddd(deep + 1, i, remain - i);
}
else {
dd[deep] = remain;
output();
sum++;
}
top--;
}
int main()
{
for (int i = 1; i <= 50; i++)
dd[i] = 0;
cin >> n >> k;
ddd(1,1,n);
cout << sum;
}
/*int dd[55];
for (int i = 1; i <= 50; i++) {
dd[i] = i;
}*/
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)。
这题没啥说的,bfs找最短路,注意下边界问题就好了。
#include<queue>
#include <iostream>
#include<stack>
int dd[501010];
using namespace std;
queue<int> dui;
stack<int> lu;
int main()
{
int x, y,sum=0;
cin >> x >> y;
if (x == y) {
cout << "0";
return 0;
}
for (int i = 1; i <= 501000; i++)
dd[i] = 0;
dui.push(x);
while (!dd[y]){
int j = dui.front();
if(j<100010)
{
if (!dd[j + 1]) {
dui.push(j + 1);
dd[j + 1] = j;
}
if (!dd[j * 2]) {
dui.push(j * 2);
dd[j * 2] = j;
}
if (j - 1 > 0)
if (!dd[j - 1]) {
dui.push(j - 1);
dd[j - 1] = j;
}
}
dui.pop();
}
lu.push(y);
while (lu.top()!=x) {
lu.push(dd[lu.top()]);
sum++;
}
lu.pop();
cout << sum<<"\n";
while (lu.size()>1) {
cout << lu.top()<<" ";
lu.pop();
}
cout << y;
}
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,按城市号递增顺序。
这道题就是信息量较多,dijiestra再加上一个找最长路的条件。
#include<vector>
#include <iostream>
#include<queue>
const int maxn = 200000000;
using namespace std;
int dist[10010];
int past[10010];
int guo[10010];
int last[10010];
vector<int> road[10010];
vector<int> cost[10010];
int main()
{
int n, m, s;
cin >> n >> m >> s;//n is city,m is traffic,s is start;
for (int i = 1; i <= n; i++)
{
dist[i] = maxn;
past[i] = 0;
guo[i] = 0;
last[i] = 0;
}
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
road[u].push_back(v);
road[v].push_back(u);
cost[u].push_back(w);
cost[v].push_back(w);
}
dist[s] = 0;
past[s] = 0;
guo[s] = 1;
last[s] = 0;
for (int i = 0; i < road[s].size(); i++) {
dist[road[s][i]] = cost[s][i];
last[road[s][i]] = s;
}
for (int i = 1; i < n; i++) {
int min = maxn+11;
int tag;
for (int t = 1; t <= n; t++) {
if (!guo[t] && dist[t] < min) {
tag = t;
min = dist[t];
}
else if (!guo[t] &&dist[t] == min) {
if (past[t] > past[tag]) {
tag = t;
}
}
}
guo[tag] = 1;
past[tag] = past[last[tag]] + 1;
for (int j = 0; j < road[tag].size(); j++) {
if (dist[road[tag][j]] > dist[tag] + cost[tag][j]) {
dist[road[tag][j]] = dist[tag] + cost[tag][j];
last[road[tag][j]] = tag;
past[road[tag][j]] = past[last[road[tag][j]]] + 1;
}
else if (dist[road[tag][j]] == dist[tag] + cost[tag][j]) {
if (past[road[tag][j]] <= past[tag]) {
last[road[tag][j]] = tag;
past[road[tag][j]] = past[last[road[tag][j]]] + 1;
}
}
}
}
for (int i = 1; i <= n; i++) {
cout << dist[i];
if (i == n)
cout << "\n";
else
cout << " ";
}
for (int i = 1; i <= n; i++) {
cout << past[i];
if (i == n)
;
else
cout << " ";
}
}