数据结构第五次上机实验

数据结构第五次上机实验

7-1 图的深度优先搜索I (100 分)

无向图 G 有 n 个顶点和 m 条边。求图G的深度优先搜索树(森林)以及每个顶点的发现时间和完成时间。每个连通分量从编号最小的结点开始搜索,邻接顶点选择顺序遵循边的输入顺序。

在搜索过程中,第一次遇到一个结点,称该结点被发现;一个结点的所有邻接结点都搜索完,该结点的搜索被完成。深度优先搜索维护一个时钟,时钟从0开始计数,结点被搜索发现或完成时,时钟计数增1,然后为当前结点盖上时间戳。一个结点被搜索发现和完成的时间戳分别称为该结点的发现时间和完成时间

输入格式:
第1行,2个整数n和m,用空格分隔,分别表示顶点数和边数, 1≤n≤50000, 1≤m≤100000.

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

输出格式:
第1到n行,每行两个整数di和fi,用空格分隔,表示第i个顶点的发现时间和完成时间1≤i≤n 。

第n+1行,1个整数 k ,表示图的深度优先搜索树(森林)的边数。

第n+2到n+k+1行,每行两个整数u和v,表示深度优先搜索树(森林)的一条边<u,v>,边的输出顺序按 v 结点编号从小到大。

输入样例:
在这里给出一组输入。例如:

6 5
1 3
1 2
2 3
4 5
5 6
输出样例:
在这里给出相应的输出。例如:

1 6
3 4
2 5
7 12
8 11
9 10
4
3 2
1 3
4 5
5 6
在这里插入图片描述
解答:根据题目描述,这道题是一道普通的DFS,只需要多维护一个时钟,并把遍历路径保存即可。
具体代码如下:

#include<bits/stdc++.h>
using namespace std;
vector<int>p[100010];
queue<int>que;
int visited[50010];
int found[50010];
int com[50010];
void DFS(int v);
int num;
int clock0=0;
int k=0;
int bian[100010];
int main()
{
	int n,i,data,m,u,v;
	cin>>n>>m;
	num=n;
	for(i=0;i<m;i++)
	{
	    cin>>u>>v;
		p[u].push_back(v);
		p[v].push_back(u);
	}
	for(i=1;i<=n;i++)
	p[i].push_back(-1);
	for(i=1;i<=n;i++)
	visited[i]=0;
	for(i=1;i<=n;i++)
	{
		if(visited[i]==0)
		DFS(i);
	}
	for(i=1;i<=n;i++)
	{
		printf("%d %d\n",found[i],com[i]);
	}
	printf("%d\n",k);
	for(i=1;i<=m;i++)
	{
		if(bian[i]!=0)
		{
		printf("%d %d\n",bian[i],i);
		}
	
	}
	
}
void DFS(int v)
{
	int i;
	clock0++;
	found[v]=clock0;
	visited[v]=1;
	for(i=0;p[v][i]!=-1;i++)
	{
		if(visited[p[v][i]]==0)
		{
			k++;
			bian[p[v][i]]=v;
			DFS(p[v][i]);
		}
		
	}
	clock0++;
	com[v]=clock0;
}

 

从小到大保存边<u,v>,可以把v当作数组下标,存u,可以避免对边集排序,从小到大遍历若不为0输出即可。

7-2 圆 (100 分)

二维平面上有n 个圆。请统计:这些圆形成的不同的块的数目。

圆形成的块定义如下: (1)一个圆是一个块; (2)若两个块有公共部分(含相切),则这两个块形成一个新的块,否则还是两个不同的块。

输入格式:
第1行包括一个整数n,表示圆的数目,n<=8000。

第2到n+1行,每行3 个用空格隔开的数x,y,r。(x,y)是圆心坐标,r 是半径。所有的坐标及半径都是不大于30000 的非负整数。

输出格式:
1个整数,表示形成的块的数目。

输入样例:
在这里给出一组输入。例如:

2
0 0 1
1 0 2
输出样例:
在这里给出相应的输出。例如:

1
在这里插入图片描述
解答:如果只是仅仅使用纯暴力法可以过4个样例,不知道最后为什么错了,这道题有点类似与上一次的连通分量问题,可以用并查集,这里我用了DFS的方法,将相交的两个圆之间加一条边使其在同一个连通分量里,再用DFS求连通分量个数。
具体代码如下:

#include<bits/stdc++.h>
using namespace std;
vector<int> p[10000];
int x[10000],y[10000],r[10000];
int count0=0;
int visited[10000];
bool m(int a,int b)
{
    if((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])-(r[a]+r[b])*(r[a]+r[b])<=0)
        return true;
    else
        return false;
}
void DFS(int v)
{
    visited[v]=1;
    for(int i=1;i<p[v].size();i++)
    {
        if(visited[p[v][i]]!=1)
            DFS(p[v][i]);
    }
}

int main()
{
	int n,i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
    	cin>>x[i]>>y[i]>>r[i];
        p[i].push_back(0);
    }
    for(i=1;i<=n;i++)
    {
        for(j=i+1;j<=n;j++)
        {
            if(m(i,j))
            {
               p[i].push_back(j);
               p[j].push_back(i);
            }
        }
    }
    for( i=1;i<=n;i++)
    {
        if(!visited[i])
        {
            DFS(i);
            count0++;
        }
    }
    printf("%d",count0);
    return 0;
}

7-3 供电 (100 分)

要给N个地区供电。每个地区或者建一个供电站,或者修一条线道连接到其它有电的地区。试确定给N个地区都供上电的最小费用。

输入格式:
第1行,两个个整数 N 和 M , 用空格分隔,分别表示地区数和修线路的方案数,1≤N≤10000,0≤M≤50000。

第2行,包含N个用空格分隔的整数P[i],表示在第i个地区建一个供电站的代价,1 ≤P[i]≤ 100,000,1≤i≤N 。

接下来M行,每行3个整数a、b和c,用空格分隔,表示在地区a和b之间修一条线路的代价为c,1 ≤ c ≤ 100,000,1≤a,b≤N 。

输出格式:
一行,包含一个整数, 表示所求最小代价。

输入样例:
在这里给出一组输入。例如:

4 6
5 4 4 3
1 2 2
1 3 2
1 4 2
2 3 3
2 4 3
3 4 4
输出样例:
在这里给出相应的输出。例如:

9
在这里插入图片描述
解答:
这是一个求最小生成树的问题,但本身节点也有权值,可以将每个点的cost先置为本身建基站的权值,再进行prim算法。

#include<bits/stdc++.h>
using namespace std;
int cost[100010];
int cost0[100010];
int path[100010];
int cost_max[100010];
int sum,max0; 
int u,v;
int visited[100010];
struct bian
{
    int name1;
    int name;
    int cost;
    bool operator<(bian a)
    {
        return cost>a.cost;
    }
};
vector<bian>p[100010];
int main()
{
    int n=0,m=0,i=0,j=0;
    cin>>n;
    cin>>m;
    for(i=1;i<=n;i++)
    {
        cin>>cost0[i];
        cost[i]=cost0[i];
    }
    if(m==0)
    {
    	for(i=1;i<=n;i++)
    	sum+=cost0[i];
    	printf("%d",sum);
    	return 0;
	}
    bian a,b;
    for(i=1;i<=m;i++)
    {
        cin>>a.name1;
        cin>>a.name;
        cin>>a.cost;
        b.name1=a.name;
        b.name=a.name1;
        b.cost=a.cost;
        p[a.name1].push_back(a);
        p[b.name1].push_back(b);
    }
    for(j=1;j<=n;j++)
    {
        max0=100000;
        for(i=1;i<=n;i++)
        {
            if(cost[i]<max0&&visited[i]==0)
            {
                max0=cost[i];
                u=i;
            }
        }
            visited[u]=1;
            for(vector<bian>::iterator k = p[u].begin();k!=p[u].end();k++)
            {
                v=k->name;
                if(k->cost<cost[v]&&visited[v]==0)
                {
                    cost[v]=k->cost;
                }
            }
    }
    for(i=1;i<=n;i++)
    {
        sum+=cost[i];
    }
    printf("%d",sum);
}

7-4 发红包 (100 分)

新年到了,公司要给员工发红包。员工们会比较获得的红包,有些员工会有钱数的要求,例如,c1的红包钱数要比c2的多。每个员工的红包钱数至少要发888元,这是一个幸运数字。

公司想满足所有员工的要求,同时也要花钱最少,请你帮助计算。

输入格式:
第1行,两个整数n和m(n<=10000,m<=20000),用空格分隔,分别代表员工数和要求数。

接下来m行,每行两个整数c1和c2,用空格分隔,表示员工c1的红包钱数要比c2多,员工的编号1~n 。

输出格式:
一个整数,表示公司发的最少钱数。如果公司不能满足所有员工的需求,输出-1.

输入样例:
在这里给出一组输入。例如:

2 1
1 2
输出样例:
在这里给出相应的输出。例如:

1777

在这里插入图片描述
解答:这个问题员工的红包之间有相互限制关系,可以使用拓扑排序,c1的红包要比c2多,则可以把2排在1的前面进行拓扑排序,将开始为入度为0的节点的红包置为888,
之后入度减为0的点的红包置为前一个节点的红包+1,这样就能满足条件的情况下花费最少。

#include<bits/stdc++.h>
using namespace std;
vector<int>p[10000];
int count0[10000];
int money[10000];
stack<int> s;
int main()
{
	int n,m,i,u,v,j;
	int sum=0;
	cin>>n>>m;
	for(i=0;i<m;i++)
	{
		cin>>u>>v;
		p[v].push_back(u);
	}
	for(i=1;i<=n;i++)
	p[i].push_back(-1);
	for(i=1;i<=n;i++)
	{
		for(j=0;p[i][j]!=-1;j++)
		count0[p[i][j]]++;
	}
	for(i=1;i<=n;i++)
	{
		if(count0[i]==0)
		{
		s.push(i);
		money[i]=0;
		}
	}
	for(i=1;i<=n;i++)
	{
		if(s.empty())
		{
		printf("-1");
		return 0;	
		}
		v=s.top();
		s.pop();
		for(j=0;p[v][j]!=-1;j++)
		{
			count0[p[v][j]]--;
			if(count0[p[v][j]]==0)
			{
				s.push(p[v][j]);
				money[p[v][j]]=money[v]+1;
			}
		}
	}
	for(i=1;i<=n;i++)
	{
		sum+=money[i];
		sum+=888;
	}
	printf("%d",sum);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于《数据结构与算法第五版》的上机实验指导,我很抱歉我不能提供具体的指导内容。但是,我可以给你一些关于数据结构与算法实验的一般指导,希望对你有所帮助。 1. 确定实验目标:首先,你需要明确每个实验的目标和要求。这包括实验要解决的问题、要使用的数据结构和算法、预期的实验结果等。 2. 设计合适的数据结构:根据实验要求,选择合适的数据结构来解决问题。例如,可以使用链表、树、图等数据结构来组织数据,以便进行相应的操作。 3. 实现算法:根据实验要求和选择的数据结构,编写相应的算法来解决问题。这包括对数据结构进行插入、删除、查找等操作的具体实现。 4. 编写测试代码:为了验证你的实现是否正确,编写测试代码来模拟各种情况下的输入和输出。通过测试代码,可以检查你的算法是否满足预期要求,并找出可能存在的问题。 5. 运行和调试:运行你的程序并进行调试。如果发现程序有错误或不符合预期结果,可以通过调试工具和打印中间结果等方式来找出问题所在,并进行修复。 6. 总结和分析结果:对实验结果进行总结和分析。比较实验结果与预期结果的差异,思考实验中遇到的问题以及可能的改进方法。 总之,进行数据结构与算法实验需要你具备一定的编程能力和理解能力。同时,根据实验要求,选择合适的数据结构和算法,并进行适当的测试和调试。希望以上指导对你有所帮助!如果你有具体的问题,欢迎继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值