JLU第四次数据结构上机实验解题报告

T1:

题目

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

INPUT

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

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

OUTPUT

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

Sample

INPUT

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

OUTPUT

2

Time limit

200ms

Memory limit

10MB

Data range

1≤n≤50000, 1≤m≤100000.1≤u,v≤n.

Solution

并查集,边连接两点如果不在同一块中将二者合并并将答案-1,在同一块中不做任何操作

赛时AC代码

#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

int fa[100005],n,m,z,x,y;

void load(){
    for(int i=1;i<=n;i++)fa[i]=i;
}

int find(int x){
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}

void hebin(int x,int y){
    fa[find(x)]=find(y);
}

int main(){
    scanf("%d%d",&n,&m);
    load();
    int ans = n;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        if(find(x) == find(y))continue;
       	hebin(x,y);
       	ans--;
    }
    printf("%d",ans);
    return 0;
}

T2:

题目

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

INPUT

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

OUTPUT

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

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

Sample

INPUT

5 2

OUTPUT

1 4
2 3
2

Time limit

100ms

Memory limit

1MB

Data range

1≤k≤n≤50.

Solution

观察到数据范围很小,dfs暴力即可

赛时AC代码

#include <bits/stdc++.h>

using namespace std;

int n,k,ce;
int to[100001],nex[100001],head[100001],val[100001];
int stac[100005],top;
int ans;

int read(){
    int x=0,y=1;char ch=getchar();
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    if(ch=='-')y=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*y;
}

void dfs(int x,int num){
	if(num == k && x == 0){
		ans++;
		for(int i=1;i<=top;i++){
			printf("%d",stac[i]);
			if(i != top)printf(" ");
		}
		printf("\n");
		return;
	}
	if(x < stac[top] || num > k)return;
	for(int i=stac[top];i<=x;i++){
		stac[++top] = i;
		dfs(x - i,num + 1);
		top--;
	}
}

int main(){
	n = read(),k = read();
	stac[0] = 1;
	dfs(n,0);
	printf("%d",ans);
	return 0;
}

T3:

题目

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

INPUT

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

OUTPUT

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

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

Sample

INPUT

2 14

OUTPUT

4
3 6 7 14

Time limit

100ms

Memory limit

5MB

Data range

1≤x,y≤100000.

Solution

可以转化为图+最短路模型,bfs即可,被优先级卡了很烦,注意优先级

赛后AC代码

#include <bits/stdc++.h>

using namespace std;

int n,k,ce;
int to[450001],nex[450001],head[200001];
bool used[200003];
int dis[200001];
int stac[100001],top;
int ans[100001];
bool flag;
queue<int> q;

int read(){
    int x=0,y=1;char ch=getchar();
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    if(ch=='-')y=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*y;
}

void add(int u,int v){
	to[++ce]=v;nex[ce]=head[u];head[u]=ce;
}

void spfa(int s){
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	q.push(s);
	used[s]=true;
	while(!q.empty()){
		int u=q.front();q.pop();
		used[u]=false;
		if(dis[u + 1] == dis[u] + 1){add(u,u + 1);if(!used[u + 1]){q.push(u + 1);used[u + 1] = 1;}}
		if(u <= 100000 && dis[u * 2] == dis[u] + 1){add(u,u * 2);if(!used[u * 2]){q.push(u * 2);used[u * 2] = 1;}}
		if(u >= 1 && dis[u - 1] == dis[u] + 1){add(u,u - 1);if(!used[u - 1]){q.push(u - 1);used[u - 1] = 1;}}
		if(dis[u + 1] > dis[u] + 1){
			dis[u + 1] = dis[u] + 1;
			add(u,u + 1);
			if(!used[u + 1]){
				q.push(u + 1);
				used[u + 1] = 1;
			}
		}
		if(u <= 100000 && dis[u * 2] > dis[u] + 1){
			dis[u * 2] = dis[u] + 1;
			add(u,u * 2);
			if(!used[u * 2]){
				q.push(u * 2);
				used[u * 2] = 1;
			}
		}
		if(u >= 1 && dis[u - 1] > dis[u] + 1){
			dis[u - 1] = dis[u] + 1;
			add(u,u - 1);
			if(!used[u - 1]){
				q.push(u - 1);
				used[u - 1] = 1;
			}
		}
	}
}

void getroad(int x){
	if(top > dis[k])return;
	if(x == k){
		if(!flag){
			for(int i=1;i<=top;i++)ans[i] = stac[i];
			flag = 1;
		} else {
			for(int i=1;i<=top;i++){
				if(stac[i] - stac[i - 1] == 1 && ans[i] - ans[i - 1] == 1)continue;
				if(stac[i] - stac[i - 1] == -1 && ans[i] - ans[i - 1] == -1)continue;
				if(stac[i] == 2 * stac[i - 1] && ans[i] == 2 * ans[i - 1])continue;
				if(stac[i] - stac[i - 1] == 1){
					for(int j=1;j<=top;j++)ans[j] = stac[j];
					return;
				}
				else if(stac[i] == 2 * stac[i - 1] && ans[i] - ans[i - 1] == -1){
					for(int j=1;j<=top;j++)ans[j] = stac[j];
						return;
				}
			}
			return;
		}
		return;
	}
	for(int i=head[x];i;i=nex[i]){
		int y = to[i];
		if(dis[y] == dis[x] + 1){
			stac[++top] = y;
			getroad(y);
			top--;
		}
	}
}

int main(){
	n = read(),k = read();
	if(n > k){
		printf("%d\n",n - k);
		for(int i=1;i<=n-k;i++){
			printf("%d",n - i);
			if(i != n - k)printf(" ");
		}
		return 0;
	}
	spfa(n);
	stac[0] = n;
	ans[0] = n;
	getroad(n);
	printf("%d\n",dis[k]);
	for(int i=1;i<=dis[k];i++){
		printf("%d",ans[i]);
		if(i != dis[k])printf(" ");
	}
	return 0;
}
//x * 2 + 3
//(x + 1) * 2 + 1

T4:

题目

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

INPUT

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

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

OUTPUT

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

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

Sample

INPUT

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

OUTPUT

0 2 6 5 13
0 1 2 1 3

Time limit

1000ms

Memory limit

10MB

Data range

1≤w≤10000。1≤s≤n≤10000, 1≤m≤100000 。

Solution

SPFA过程中统计经过城市数量取max即可

赛时AC代码

#include <bits/stdc++.h>

using namespace std;

int n,m,s,ce;
int to[200001],nex[200001],head[10001],val[200001];
int used[100003];
int dis[10003];
int mxvis[100003];
queue<int> q;

int read(){
    int x=0,y=1;char ch=getchar();
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    if(ch=='-')y=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*y;
}

void add(int u,int v,int w){
	to[++ce]=v;nex[ce]=head[u];head[u]=ce;val[ce]=w;
}

void spfa(int s){
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	q.push(s);
	used[s]=true;
	while(!q.empty()){
		int u=q.front();q.pop();
		used[u]=false;
		for(int i=head[u];i;i=nex[i]){
			int v=to[i],w=val[i];
			if(dis[u]+w<dis[v]){
				mxvis[v] = mxvis[u] + 1;
				dis[v]=dis[u]+w;
				if(!used[v]){
					used[v]=true;
					q.push(v);
				}
			} else if(dis[u] + w == dis[v])
				mxvis[v] = max(mxvis[v],mxvis[u] + 1);
		}
	}
}

int main(){
	n = read(),m = read(),s = read();
	for(int i=1;i<=m;i++){
		int x = read(),y = read(),z = read();
		add(x,y,z);
		add(y,x,z);
	}
	spfa(s);
	for(int i=1;i<=n;i++){
		printf("%d",dis[i]);
		if(i != n)printf(" ");
	}
	printf("\n");
	for(int i=1;i<=n;i++){
		printf("%d",mxvis[i]);
		if(i != n)printf(" ");
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值