7-1 连通分量 (100 分)
作者 :谷方明
单位 :吉林大学
代码长度限制 :16 KB
时间限制 :200 ms
内存限制 :10 MB
无向图 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
我使用了vector保存路径,下标表示路径出发的结点,vector中存的值表示路径终止的结点。正如前面所说的,这样保存的是有向图,无向图应该保存一条由起点到终点和由终点到起点两条有向边。
#include<bits/stdc++.h>
using namespace std;
/*文件输入输出*/
const int MAXN=1e5+5;
int v[MAXN];
vector<int>q[MAXN];
void dfs(int a){
//cout<<a<<endl;
if(v[a]==1) return;
v[a]=1;
for(int i=0;i<q[a].size();i++){
dfs(q[a][i]);
}
}
int main(){
int n;
long long m;
long long count=0;
scanf("%d%lld",&n,&m);
for(long long i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
q[u].push_back(v);
q[v].push_back(u);
}
for(int i=1;i<=n;i++) v[i]=0;
for(int i=1;i<=n;i++){
if(v[i]==0){
dfs(i); count++;
}
}
printf("%lld\n",count);
return 0;
}
7-2 整数拆分 (100 分)
作者 :谷方明
单位 :吉林大学
代码长度限制 :16 KB
时间限制 :100 ms
内存限制 :1 MB
整数拆分是一个古老又有趣的问题。请给出将正整数 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
- 第二题也是一道不太难的题呢!
(结果考试的时候四道题一道没做出来QAQ)就是使用DFS+回溯法。容器有用过vector和数组,数组可以直接覆盖原来的值,实现隐形的回溯,所以最后选用了数组。
这道题在考场上一直出的问题是方案总数是对的,但是每个方案中数的大小会小一个1。是递归调用函数和赋值两步的顺序出了问题。(我到底是多么不清醒才会犯这种错误啊)
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
long long q[MAXN];
int n,k;
long long Count=0;
void B(int pre,int a,int b) { //已经放进了几个数,剩余和
//cout<<"f"<<a<<b<<endl;
//system("pause");
if(a==k) {
if(b==0) {
for(int i=0; i<k; i++) {
printf("%lld",q[i]);
printf("%c",i==k-1?'\n':' ');
}
Count++;
}
return;
}
if(b<=0) return;
for(int i=pre; i<=b; i++) {
q[a]=i;
B(i,a+1,b-i);
}
}
int main() {
scanf("%d%d",&n,&k);
//cout<<n<<k<<endl;
B(1,0,n);
printf("%lld\n",Count);
}
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
- 这道题我一开始用的是DFS
(因为我只会DFS),但是后来发现这是个无限图问题,DFS能找到无数个解,但是无法找出最优解。听了其他同学的讲解,才知道应该使用BFS求最优解。
用了BFS后,有两个点会内存超限,通过看其他同学的题解,我注意到了题目中给出的x,y的范围,根据有限的三种变换可知,超出这个范围的数应该不会出现在最优解中,所以对这个部分进行了限制。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
int v[MAXN];
int step[MAXN];
int stepnum[MAXN];
int result[MAXN];
queue<int>q;
int x,y;
void bfs(){
while(!q.empty()){
int u=q.front();
if(u==y) return;
q.pop();
if(!v[u+1]&&u+1<=1e5&&u+1>=1){
v[u+1]=1;
step[u+1]=u;
stepnum[u+1]=stepnum[u]+1;
// cout<<u+1<<" "<<stepnum[u+1]<<endl;
q.push(u+1);
}
if(!v[2*u]&&2*u<=1e5&&2*u>=1){
v[2*u]=1;
step[u*2]=u;
stepnum[2*u]=stepnum[u]+1;
//cout<<2*u<<" "<<stepnum[2*u]<<endl;
q.push(2*u);
}
if(!v[u-1]&&u-1<=1e5&&u-1>=1){
v[u-1]=1;
step[u-1]=u;
stepnum[u-1]=stepnum[u]+1;
//cout<<u-1<<" "<<stepnum[u-1]<<endl;
q.push(u-1);
}
}
}
int main(){
scanf("%d%d",&x,&y);
v[x]=1; step[x]=0; stepnum[x]=0;
q.push(x);
bfs();
int tmp=y;
int count=0;
while(tmp){
result[count++]=tmp;
// cout<<tmp<<" "<<stepnum[tmp]<<endl;
tmp=step[tmp];
}
printf("%d\n",stepnum[y]);
for(int i=count-2;i>=0;i--){
printf("%d",result[i]);
printf("%c",i==0?'\n':' ');
}
return 0;
}
7-3 数字变换 (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<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int visited[MAXN];
vector<int>q[MAXN];
vector<int>cost[MAXN];
int dist[MAXN];//路径长度
int path[MAXN];//前一个结点
int c[MAXN];
int n,m,s;
void Dijkstra(int head) {
// cout<<"Dijkstra"<<endl;
for (int i = 1; i <= n; i++) {
path[i] = -1;
dist[i] = MAXN;
visited[i] = 0;
c[i]=-1;
}
dist[head] = 0;
visited[head] = 1;
c[head]=0;
int u = head;
for (int i = 1; i < n; i++) {
//cout<<u<<endl;
//cout<<q[u].size()<<endl;
for (int j = 0; j < q[u].size(); j++) {
int k = q[u][j];
if (!visited[k] && dist[u] + cost[u][j] < dist[k]) {
dist[k] = dist[u] + cost[u][j];
path[k] = u;
c[k]=c[u]+1;
}
if(!visited[k] && dist[u] + cost[u][j] == dist[k]){
if(c[u]+1>c[k]) {
c[k]=c[u]+1;
path[k]=u;
}
}
}
int ldist = MAXN;
for (int j = 1; j <= n; j++) {
if (dist[j] < ldist&&visited[j] == 0) {
ldist = dist[j];
u = j;
}
}
visited[u] = 1;
}
for (int k = 1; k <= n; k++) {
printf("%d",dist[k]);
printf("%c",k==n?'\n':' ');
}
for (int k = 1; k <= n; k++) {
printf("%d",c[k]);
printf("%c",k==n?'\n':' ');
}
}
int main() {
//int n,m,k;
scanf("%d%d%d",&n,&m,&s);
for(int i=1; i<=m; i++) {
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
//cout<<u<<v<<d;
q[u].push_back(v);
cost[u].push_back(d);
q[v].push_back(u);
cost[v].push_back(d);
}
Dijkstra(s);
}