数据结构第四次结题报告

连通分量 (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遍历一遍即可

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
struct edge{
	int u,v;
	edge(int a,int b){
		u=a;
		v=b;

	}
};
vector<edge> G[N];
int n,vis[N];
void init(){
	for(int i=1;i<=n;i++)G[i].clear();
}
void dfs(int u){
	vis[u]=1;
	//cout<<u<<" ";
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].v;
		if(!vis[v]){
			dfs(v);
		}
	}
}
int m,u,v;
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>u>>v;
		G[u].push_back(edge(u,v));
		G[v].push_back(edge(v,u));
	}
	int sum=0;
	for(int i=1;i<=n;i++){
    if(!vis[i]){
	dfs(i);
	sum++;
    }
	}
	cout<<sum<<endl;
	return 0;
}

整数拆分 (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>
#include<algorithm>
using namespace std;
int ntsjjg[100],n,k,ans = 0;
void dfs(int s,int q,int up){
	if(q == k && s==0){
		ans++;
		for(int i = 1; i <= k; ++i){
			printf("%d", ntsjjg[i]);
			if(i!= k)	printf(" ");
			else printf("\n");
		}
	}
	for(int i = up;i<=s;++i){
		ntsjjg[q+1] = i;
		dfs(s-i,q+1,i);
	}
}
int main(){
	cin>>n>>k;
    if(k>n){
        printf("0");
      return 0;
    }
    if(k==1){
    cout<<n<<endl;
    cout<<1<<endl;
        return 0;
}

	dfs(n,0,1);
	printf("%d",ans);
	printf("\n");
	return 0;
}


数字变换 (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

思路

可以理解为找最短路的算法。

代码


#include<bits/stdc++.h>
using namespace std;
int rake(int u,int t);
int ro;
int x,y;
struct vp{
int temp,t_emp;
vp(int a,int b):temp(a),t_emp(b){}
};
int visit[200010];
int road[200010];
void bfs(){
queue<vp>q;
q.push(vp(x,0));
visit[x]=1;
while(!q.empty()){
    vp c=q.front();
    q.pop();
    if(c.temp==y){
        ro=c.t_emp;
        return ;
    }
    for(int i=1;i<=3;i++){
        int z=rake(c.temp,i);
        if(z<200000&&!visit[z]){
            visit[z]=1;
            road[z]=c.temp;
            q.push(vp(z,c.t_emp+1));
        }
    }
}
}
int main(){
cin>>x>>y;
memset(road,-1,sizeof(road));
bfs();
int ok=road[y];
stack<int> ans;
ans.push(y);
while(ok!=-1){
    ans.push(ok);
    ok=road[ok];
}
if(!ans.empty()) ans.pop();
cout<<ro<<endl;
while(!ans.empty()){
    cout<<ans.top();
    if(ans.size()!=1)
        cout<<" ";
    else cout<<endl;
    ans.pop();
}

}
int rake(int u,int t){
if(t==1){
    return u+1;
}
else if(t==2){
    return u*2;
}
else return u-1;
}



旅行 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 <vector>
#include <queue>
using namespace std;
int Data[10001];
vector<pair<int,int> >v[10001];
int n;
int m;
void BuildGraph()
{
	for(int i=1;i<=n;i++)
		Data[i]=1;

	int _u,_v,cost_uv;
	for(int i=1;i<=m;i++)
	{
        scanf("%d %d %d",&_u,&_v,&cost_uv);
		v[_u].push_back(make_pair(_v,cost_uv));
		v[_v].push_back(make_pair(_u,cost_uv));

	}

}
#define MaxCost 1e5;
int CSum[10001];
int PrePath[10001];
int SumPos[10001]={0};

void Dijkstra(int begin)
{
	priority_queue<pair<int,int> > q;

	for(int i=1;i<=n;i++)
	{
		CSum[i]=MaxCost;
		PrePath[i]=-1;
	}
	CSum[begin]=0;
	q.push(make_pair(0,begin));


	while(!q.empty())
	{
		int NextIndex=q.top().second;
		q.pop();

		for(vector<pair<int,int> >::iterator it=v[NextIndex].begin();it!=v[NextIndex].end();it++)
			if(CSum[it->first]>CSum[NextIndex]+it->second)
			{
				CSum[it->first]=CSum[NextIndex]+it->second;
				SumPos[it->first]=SumPos[NextIndex]+1;
				q.push(make_pair(CSum[it->first],it->first));

			}
			else if(CSum[it->first]==CSum[NextIndex]+it->second)
			{
				if(SumPos[it->first]<SumPos[NextIndex]+1)
				{
					//cout<<"SumPos["<<it->first<<"]=SumPos["<<NextIndex<<"]+1="<<SumPos[NextIndex]+1<<endl;
					SumPos[it->first]=SumPos[NextIndex]+1;
				}
			}
	}

}


int main()
{
    int begin;
    scanf("%d %d %d",&n,&m,&begin);
	BuildGraph();
	Dijkstra(begin);
    printf("%d",CSum[1]);
    for(int i=2;i<=n;i++)
	{
        printf(" %d",CSum[i]);
	}
    printf("\n%d",SumPos[1]);
	for(int i=2;i<=n;i++)
	{
        printf(" %d",SumPos[i]);
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值