HNUCM-2024年春季学期《算法分析与设计》练习13

问题 A: 菱形图案

题目描述

KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的菱形图案。

输入

多组输入,一个整数(2~20)。

输出

针对每行输入,输出用“*”组成的菱形,每个“*”后面有一个空格。每输出一个菱形的后面需要空一行。

样例输入 Copy

2

3

4

样例输出 Copy

    *

   * *

  * * *

   * *

    *

    *

   * *

  * * *

 * * * *

  * * *

   * *

    *

    *

   * *

  * * *

 * * * *

* * * * *

 * * * *

  * * *

   * *

    *

while True:
    n1 = int(input())
    i = n1
    while i >= 0:
        print(' ' * i, end='')
        print('* ' * (n1 + 1 - i), end='')
        print(' ' * (i - 1))
        i -= 1
    i = 1
    while i <= n1:
        print(' ' * i, end='')
        print('* ' * (n1 + 1 - i), end='')
        print(' ' * (i - 1))
        i += 1
    print('')

  问题 B:X星人的礼物

题目描述

六一儿童节到了,X星人宝宝收到了很多很多礼物。他决定把这些礼物装到自己的礼物箱中。为此,他准备了很多个型号相同的礼物箱,每个礼物箱能够装礼物的最大重量都是一样的。但是X星人宝宝不希望在一个礼物箱里面装太多礼物(可能担心礼物会被压坏吧),每个礼物箱最多只允许装2个礼物。
假设X星人宝宝收到了N个礼物,现在给出每一个礼物的重量和一个礼物箱的最大装载量,请你编写一个程序计算X星人宝宝最少要用多少个礼物箱才能够把所有的礼物都装完。

输入

单组输入。
每组两行,第1行输入两个正整数,分别表示礼物的数量N和每个礼物箱的最大装载量C,其中1<=N<=1000,1<=C<=100,两者之间用英文空格隔开。
第2行输入N个不超过100的正整数,分别表示每一个礼物的重量,两两之间用英文空格隔开。
输入保证最重的礼物的重量<=C。

输出

针对所输出的数据,输出将所有的礼物全部都装完所需的礼物箱的最少个数。

样例输入 Copy

5 80

20 70 40 30 10

样例输出 Copy

3

n, c = map(int, input().split())
aa, cnt = [int(i) for i in input().split()], 0
i, j, _ = 0, n - 1, aa.sort()
while i < j:
    if aa[i] + aa[j] <= c:
        cnt, i, j = cnt + 1, i + 1, j - 1
    else:
        cnt, j = cnt + 1, j - 1
print(cnt) if i != j else print(cnt + 1)

问题 C:隔离14天

题目描述
     一辆汽车上有一个需分开的乘客,那么该汽车上所有的人都被认为是需分开者,全部需要自行居家分开或者集中14天。现在假定编号为0的乘客不能在一起,请编写一个程序统计需分开的总人数(包括编号为0的乘客)。

输入

第1行的第1个数字n表示总人数,第2个数字m表示汽车数量;从第2行开始,接下来的m行表示每辆汽车的司乘人员总人数和人员编号(人员编号是一个固定值,可以对应于我们的身份证号码),每一行的第1个数字k表示该汽车的司乘人员总数,接下来的k个数字表示每一个人的编号。

输出

需要被分开的总人数。

样例输入 Copy

100 4

2 1 2

5 10 13 11 12 14

2 0 1

2 99 2

样例输出 Copy

4

def find(y, k):
    for x in y:
        for j in range(len(k)):
            if x in k[j]:
                for z in k[j]:
                    y.append(z)
                k[j] = list('wO')
while True:
    n1, m1 = map(int, input().split())
    y = []
    k = [[] for i in range(m1)]
    for i in range(m1):
        k[i] = list(map(int, input().split()))
        del k[i][0]
    for i in range(m1):
        if 0 in k[i]:
            for x in k[i]:
                y.append(x)
            k[i] = list('wO')
    find(y, k)
    print(len(set(y)))

 问题 D:最小生成树(Kruskal)

题目描述

编程实现Kruskal算法,求图的最小生成树(MST)的权重。

输入

每组数据分为两个部分,第一部分为图的点数n,和边数m, 
第二部分为m行,每一行输入三个数字,前两个为两个顶点的编号,第三个为边权重。 

输出

最小生成树的权重。

样例输入 Copy

3 3

0 1 10

0 2 15

1 2 50

样例输出 Copy

25

while True:
    n,m=map(int,input().split())
    a1 = [0 for i in range(m)]
    b1 = [0 for i in range(m)]
    c = [0 for i in range(m)]
    d = [0 for i in range(n)]
    count=1
    sum=0
    for i in range(0,m):
        q,p,num=map(int,input().split())
        a1[i]=q
        b1[i]=p
        c[i]=num
    for i in range(0,m-1):
        for j in range(0,m-1):
            if c[j]>c[j+1]:
                    t=a1[j]
                    a1[j]=a1[j+1]
                    a1[j+1]=t
                    t=b1[j]
                    b1[j]=b1[j+1]
                    b1[j+1]=t
                    t = c[j]
                    c[j] = c[j + 1]
                    c[j + 1] = t
    for i in range(0,n-1):
        if d[a1[i]]==0 and d[b1[i]]==0:
                d[a1[i]]=count
                d[b1[i]]=count
                count+=1
                sum+=c[i]
        elif d[a1[i]]!=0 and d[b1[i]]==0:
                d[b1[i]]=d[a1[i]]
                sum+=c[i]
        elif d[a1[i]]==0 and d[b1[i]]!=0:
                d[a1[i]]=d[b1[i]]
                sum+=c[i]
        elif d[a1[i]]!=0 and d[b1[i]]!=0 and d[a1[i]]!=d[b1[i]]:
            for j in range(0,n):
                if d[j]==d[b1[i]]:
                    d[j]=d[a1[i]]
            sum+=c[i]
    print(sum)

问题 E:搭建电路

题目描述

明明迷上了一个搭建电路的游戏。
在游戏中,每次在两个电子元件之间增加一条有效电路(两个元件之间先前没有电路相连)都将获得相应的积分奖励。
已知电子元件数量n和部分电子元件之间的奖励积分值。如何构建一个有效电路将所有元件全部连接起来,并且可以得到最多的积分奖励。

输入

每组输入数据包含m+1行。
第1行输入两个正整数n和m,其中n表示电子元件数量(n<=100),m表示提供了m对电子元件之间的奖励积分值(m<=1000)。两个正整数之间用空格隔开。
第2行到第m+1行对应m对电子元件及其对应的奖励积分值,每一行包含三个正整数,第1个和第2个整数表示电子元件编号(从1开始),第3个整数表示两个元件之间搭建电路的奖励积分num(num<1e9)。整数之间用空格隔开。

输出

每组输出占1行,输出一个正整数,即最多可以得到的积分奖励值。如果没有办法把所有元件全部连接起来,则输出“No solution.”。

样例输入 Copy

3 3

1 2 10

1 3 20

2 3 30

样例输出 Copy

50

while True:
    n,m=map(int,input().split())
    a1 = [0 for i in range(m)]
    b = [0 for i in range(m)]
    c = [0 for i in range(m)]
    d = [0 for i in range(n)]
    count=1
    t=0
    sum=0
    for i in range(0,m):
        q,p,num=map(int,input().split())
        a1[i]=q-1
        b[i]=p-1
        c[i]=num
    if m<n-1:
        print("No solution.")
    else:
        for i in range(0,m-1):
            for j in range(0,m-1):
                if c[j]<c[j+1]:
                    t=a1[j]
                    a1[j]=a1[j+1]
                    a1[j+1]=t
                    t=b[j]
                    b[j]=b[j+1]
                    b[j+1]=t
                    t = c[j]
                    c[j] = c[j + 1]
                    c[j + 1] = t
        for i in range(0,m):
            if d[a1[i]]==0 and d[b[i]]==0:
                d[a1[i]]=count
                d[b[i]]=count
                count+=1
                sum+=c[i]
            elif d[a1[i]]!=0 and d[b[i]]==0:
                d[b[i]]=d[a1[i]]
                sum+=c[i]
            elif d[a1[i]]==0 and d[b[i]]!=0:
                d[a1[i]]=d[b[i]]
                sum+=c[i]
            elif d[a1[i]]!=0 and d[b[i]]!=0 and d[a1[i]]!=d[b[i]]:
                flag=d[b[i]]
                for j in range(0,n):
                    if d[j]==flag:
                        d[j]=d[a1[i]]
                sum+=c[i]
        flag=0
        for i in range(0,n-1):
            if d[i]!=d[i+1]:
                flag=1
        if flag==0:
            print(sum)
        else:
            print("No solution.")
 

 问题 F: 最小生成树(Prim)

题目描述

使用Prim算法求图的最小生成树(MST)

输入

每组数据分为两个部分,第一部分为图的点数n,和边数m,
第二部分为m行,每一行输入三个数字,前两个为两个顶点的编号,第三个为边权重。

输出

最小生成树,输出时按照边的两个端点的升序输出。(先看左端点,再看右端点,端点不换位置)

样例输入 Copy

3 3

0 1 10

0 2 15

1 2 50

样例输出 Copy

0 1 10

0 2 15

while True:
    try:
        n1, m = map(int, input().split())
        maze = [list(map(int, input().split())) for _ in range(m)]
        _, cnt, visited, res = maze.sort(key=lambda x: x[2]), 1, [], []
        a, b, c = maze.pop(0)
        visited.extend([a, b]), res.append([a, b, c])
        while cnt < n1 - 1:
            for i in range(len(maze)):
                a, b, c = maze[i]
                if (a not in visited or b not in visited) and (a in visited or b in visited):
                    visited.append(a) if a not in visited else visited.append(b)
                    _, _, cnt = res.append([a, b, c]), maze.pop(i), cnt + 1
                    break
        res.sort()
        for a, b, c in res:
            print(a, b, c)
    except:
        break

问题G:台球碰撞

题目描述

在平面直角坐标系下,台球桌是一个左下角在(0,0),右上角在(L,W)的矩形。有一个球心在(x,y),半径为R的圆形母球放在台球桌上(整个球都在台球桌内)。受撞击后,球沿极角为a的射线(即:x正半轴逆时针旋转到此射线的角度为a)飞出,每次碰到球桌时均发生完全弹性碰撞(球的速率不变,反射角等于入射角)。

如果球的速率为vs个时间单位之后球心在什么地方?

输入

输入文件最多包含25组测试数据,每个数据仅一行,包含8个正整数L,W,x,y,R,a,v,s(100<=L,W<=105,1<=R<=5, R<=x<=L-RR<=y<=W-R, 0<=a<360, 1<=v,s<=105),含义见题目描述。L=W=x=y=R=a=v=s=0表示输入结束,你的程序不应当处理这一行。

输出

对于每组数据,输出仅一行,包含两个实数xy,表明球心坐标为(x,y)。xy应四舍五入保留两位小数。

样例输入 Copy

100 100 80 10 5 90 2 23

110 100 70 10 5 180 1 9999

0 0 0 0 0 0 0 0

样例输出 Copy

80.00 56.00

71.00 10.00

#include<stdio.h>
#include<math.h>
void ZB(double L, double W, double x, double y, double R, double a, double v, double s, double Dx, double Dy);
int main()
{
	double L[26], W[26], x[26], y[26], R[26], a[26], v[26], s[26];
	double Dx = 0, Dy = 0;
	int i,j=0;
	for ( i = 0; i < 26; i++)
	{
		scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &L[i], &W[i], &x[i], &y[i], &R[i], &a[i], &v[i], &s[i]);
		if (L[i] == 0 && W[i] == 0 && x[i] == 0 && y[i] == 0 && R[i] == 0 && a[i] == 0 && v[i] == 0 && s[i] == 0)
		{
			j = i;
			break;
		}
	}
	for ( i = 0; i < j; i++)
	{
		ZB(L[i], W[i], x[i], y[i], R[i], a[i], v[i], s[i],Dx,Dy);
	}
	return 0;
}
void ZB(double L, double W, double x, double y, double R, double a, double v, double s,double Dx,double Dy)
{
	double l, w, x0, y0;
	a = a / 180.0 * acos(-1);
	l = L - 2 * R;
	w = W - 2 * R;
	x0 = x - R;
	y0 = y - R;
	Dx = fabs(v * s * cos(a) + x0);
	Dy = fabs(v * s * sin(a) + y0);
	while (Dx > 2 * l)
	{
			Dx -= 2 * l;
	}
	while (Dy > 2 * w)
	{
		Dy -= 2 * w;
	}
	if (Dx > l && Dx < 2 * l) Dx = 2 * l - Dx;
	else;
	if (Dy > w && Dy < 2 * w) Dy = 2 * w - Dy;
	else;
	printf("%.2lf %.2lf\n", Dx + R, Dy + R);
	
}

 问题H:球场的数目

题目描述

在上题中,假设球场的图形周长为p,一共有多少种可能的球场?
例如,p<8时没有符合要求的球场,p=8时有2种球场:

p=10有9种球场:

要求输出方案总数模987654321的值。

输入

输入文件最多包含25组测试数据,每个数据仅包含一行,有一个整数p(1<=p<=109),表示场的图形周长。p=0表示输入结束,你的程序不应当处理这一行。

输出

对于每组数据,输出仅一行,即满足条件的场总数除以987654321的余数。

样例输入 Copy

7

8

9

10

0

样例输出 Copy

0

2

0

9

#include<stdio.h>
#include<cstring>
#include<iostream>
using namespace std;
#define ll long long
#define mod 987654321
struct ju
{
    ll m[2][2];
}ans,base;
ju multi(ju a,ju b)
{
    ll temp[2][2];
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            temp[i][j]=a.m[i][j];
        }
 
    }
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            a.m[i][j]=0;
            for(int w=0;w<2;w++)
                a.m[i][j]+=(temp[i][w]*b.m[j][w])%mod;
        }
    }
    return a;
}
int pow(int n)
{
    base.m[0][0] = base.m[0][1] = base.m[1][0] = 1;
    base.m[1][1] = 0;
    ans.m[0][0] = ans.m[1][1] = 1;  // ans 初始化为单位矩阵
    ans.m[0][1] = ans.m[1][0] = 0;
    //n-=4;
    while(n)
    {
        if(n&1)
        {
            ans=multi(base,ans);
        }
        base=multi(base,base);
        n>>=1;
    }
    return ans.m[0][0];
}
int main()
{
    int n;
    while(scanf("%d",&n)&&n!=0)
    {
        if(n<8||n&1) printf("0\n");
        else
        {
            ll kk1=(pow(n-4)-n/2+1)%mod;
            if(kk1<0) kk1+=mod;
            printf("%lld\n",kk1%mod);
        }
    }
    return 0;
}

 点赞加关注是您对我的认可,谢谢支持,再次感谢。

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您讲解一下 HNUCM 最小生成树(Prim)的算法过程。 首先,Prim 算法是一种贪心算法,用于求解带权无向连通图的最小生成树。下面是具体的算法过程: 1. 选取任意一个顶点作为起点,将其加入到生成树中。 2. 找到与已经加入到生成树中的顶点相邻的所有顶点,并计算它们与生成树的距离。 3. 从这些顶点中选取距离最小的顶点,将其加入到生成树中。 4. 重复步骤2和3,直到生成树中包含了所有的顶点。 在具体实现时,可以使用一个数组来记录每个顶点是否已经加入到生成树中,以及另一个数组来记录每个顶点与生成树的距离。每次选择距离最小的顶点时,可以使用一个最小堆来优化。 至于 HNUCM 最小生成树 Prim 算法的具体实现,可以参考以下代码: ```python import heapq def prim(graph): n = len(graph) visited = [False] * n distance = [float('inf')] * n distance[0] = 0 heap = [(0, 0)] result = 0 while heap: (d, u) = heapq.heappop(heap) if visited[u]: continue visited[u] = True result += d for v, weight in graph[u]: if not visited[v] and weight < distance[v]: distance[v] = weight heapq.heappush(heap, (weight, v)) return result ``` 这段代码实现了 HNUCM 最小生成树 Prim 算法的过程,其中 graph 是一个邻接表表示的带权无向连通图,每个元素是一个二元组 (v, w),表示从节点 u 到节点 v 有一条边权为 w 的边。算法的返回值是最小生成树的总权值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值