NEUQ2020-实验班-训练001(1-5题)

NEUQ2020-实验班-训练001(1-5题)

7-1 最短路径算法(Floyd-Warshall)

题目:

在带权有向图G中,求G中的任意一对顶点间的最短路径问题,也是十分常见的一种问题。

解决这个问题的一个方法是执行n次迪杰斯特拉算法,这样就可以求出每一对顶点间的最短路径,执行的时间复杂度为O(n​3)。 而另一种算法是由弗洛伊德提出的,时间复杂度同样是O(n​3​​),但算法的形式简单很多。

在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并使用Floyd算法求出每一对顶点间的最短路径长度。

输入格式:

输入的第一行包含1个正整数n,表示图中共有n个顶点。其中n不超过50。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。 当i和j相等的时候,保证对应的整数为0。

输出格式:

共有n行,每行有n个整数,表示源点至每一个顶点的最短路径长度。

如果不存在从源点至相应顶点的路径,输出-1。对于某个顶点到其本身的最短路径长度,输出0。

请在每个整数后输出一个空格,并请注意行尾输出换行。

输入样例:

4
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

输出样例:

0 3 2 1
6 0 4 7
2 5 0 3
3 6 1 0

题目分析:

简单的数据结构中的Floyd算法的实现与应用,只是本题需要注意的两个点是:1.在输入数据时,要将那些不相邻的邻点的权值由0变成inf。2.在输出数据时,应注意要将inf转为-1以后再输出。

算法思想:

Floyd-傻子也能看懂的弗洛伊德算法这个文章写的真心不错,大家阅读之后应该会有所收益。

具体AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int e[60][60];
    int n;
    int inf = 99999999; 
    cin>>n;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cin>>e[i][j];
            if (i != j&&e[i][j]==0)
            {
               e[i][j] = inf;
            }
        }    
    }
    for (int k = 1; k <= n; k++)
    {
         for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                    if (e[i][j] > e[i][k] + e[k][j])
                    {
                        e[i][j] = e[i][k] + e[k][j];
                    }
            } 
        }           
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if(e[i][j]==inf)
            {
                e[i][j] = -1;
            }
            cout<<e[i][j]<<' ';
        }
        cout<<endl;
    }
    return 0;
}

7-2 栈的实现及基本操作

题目:

给定一个初始为空的栈和一系列压栈、弹栈操作,请编写程序输出每次弹栈的元素。栈的元素值均为整数。

输入格式:

输入第1行为1个正整数n,表示操作个数;接下来n行,每行表示一个操作,格式为1 d或0。1 d表示将整数d压栈,0表示弹栈。n不超过20000。

输出格式:

按顺序输出每次弹栈的元素,每个元素一行。若某弹栈操作不合法(如在栈空时弹栈),则对该操作输出invalid。

输入样例:

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

7
1 1
1 2
0
0
0
1 3
0

输出样例:

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

2
1
invalid
3

思路:

只要记住栈的特点即可:先进后出,然后利用数组模拟上题所说的过程即可!
扩展资料:

AC代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[100000];
    int n;
    cin>>n;
    int i=0;
    while(n--)
    {
        int x;
        cin>>x;
        if(x==1)
        {
            int y;
            cin>>y;
            a[i] = y;
            i++;
        }
        else if(x==0) 
        {
            if(i-1<0)
            {
                cout<<"invalid"<<endl;
            }
            else
            {
                 cout<<a[i-1]<<endl;
                 i--;
            }
        }
    }
    return 0;
} 

7-3 队列的实现及基本操作

题目:

给定一个初始为空的队列和一系列入队、出队操作,请编写程序输出每次出队的元素。队列的元素值均为整数。

输入格式:

输入第1行为1个正整数n,表示操作个数;接下来n行,每行表示一个操作,格式为1 d或0。1 d表示将整数d入队,0表示出队。n不超过20000。

输出格式:

按顺序输出每次出队的元素,每个元素一行。若某出队操作不合法(如在队列空时出队),则对该操作输出invalid。

输入样例:

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

7
1 1
1 2
0
0
0
1 3
0

输出样例:

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

1
2
invalid
3
**

思路:

与栈那个题一样,其实栈和队列都属于线性表的一部分,但不同的是,栈是先进后出,队列是先进先出,这个题可以用数组模拟普通队列过去,但建议大家可以尝试用一下循环队列去做这个题,因为循环队列可以更好的利用系统的空间。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[100000];
    int n;
    cin>>n;
    int i=0;
    int j=0;
    while(n--)
    {
        int x;
        cin>>x;
        if(x==1)
        {
            int y;
            cin>>y;
            a[i] = y;
            i++;
        }
        else if(x==0) 
        {
            if(j-1>=i-1)
            {
                cout<<"invalid"<<endl;
            }
            else
            {
                 cout<<a[j]<<endl;
                 j++;
            }
        }
    }
    return 0;
} 

7-4 字符串的冒泡排序

题目:

我们已经知道了将N个整数按从小到大排序的冒泡排序法。本题要求将此方法用于字符串序列,并对任意给定的K(<N),输出扫描完第K遍后的中间结果序列。

输入格式:

输入在第1行中给出N和K(1≤K<N≤100),此后N行,每行包含一个长度不超过10的、仅由小写英文字母组成的非空字符串。

输出格式:

输出冒泡排序法扫描完第K遍后的中间结果序列,每行包含一个字符串。

输入样例:

6 2
best
cat
east
a
free
day

输出样例:

best
a
cat
day
east
free

思路:

直接把string类型看作int去做就可以,原理与数字的冒泡排序基本一致,只不过之前是定义整型数组,而现在该题是需要我们定义为字符串数组!

AC代码

#include<iostream>
using namespace std;
int main()
{
	int n,k;
	cin >> n >> k;
	string s[101];
	for(int i=0;i<n;i++)
    {
		cin>>s[i];
	}
	for(int i=0;i<k;i++)
    {
		for(int j=0;j<n-1;j++)
        {
			if(s[j]>s[j+1])
            {
				string t=s[j];
				s[j]=s[j+1];
				s[j+1]=t;
			}
		}
	}
	for(int i=0;i<n-1;i++)
    {
		cout<<s[i]<<endl;
	}
	cout<<s[n-1];
	return 0;
} 

7-5 打印选课学生名单

题目:

假设全校有最多40000名学生和最多2500门课程。现给出每个学生的选课清单,要求输出每门课的选课学生名单。

输入格式:

输入的第一行是两个正整数:N(≤40000),为全校学生总数;K(≤2500),为总课程数。此后N行,每行包括一个学生姓名(3个大写英文字母+1位数字)、一个正整数C(≤20)代表该生所选的课程门数、随后是C个课程编号。简单起见,课程从1到K编号。

输出格式:

顺序输出课程1到K的选课学生名单。格式为:对每一门课,首先在一行中输出课程编号和选课学生总数(之间用空格分隔),之后在第二行按字典序输出学生名单,每个学生名字占一行。

输入样例:

10 5
ZOE1 2 4 5
ANN0 3 5 2 1
BOB5 5 3 4 2 1 5
JOE4 1 2
JAY9 4 1 2 5 4
FRA8 3 4 2 5
DON2 2 4 5
AMY7 1 5
KAT3 3 5 4 2
LOR6 4 2 4 1 5

输出样例:

1 4
ANN0
BOB5
JAY9
LOR6
2 7
ANN0
BOB5
FRA8
JAY9
JOE4
KAT3
LOR6
3 1
BOB5
4 7
BOB5
DON2
FRA8
JAY9
KAT3
LOR6
ZOE1
5 9
AMY7
ANN0
BOB5
DON2
FRA8
JAY9
KAT3
LOR6
ZOE1

超时的思路:

定义一个结构体,包含学生的名字,选课数量,选课种类。
在输入数据的同时,定义一个数组,对每门课的数量进行统计,方便在后面输出
利用sort()函数,加上bool cmp()函数,使得结构体学生的姓名按照字典序进行排序,方便后续的输出
输出时,遍历每一个学生的每门课程,然后若有,则输出该学生的名字。

最后一个测试点超时的代码:

#include<bits/stdc++.h>
using namespace std;
struct Stu
{
    string  name;
    int x;
    int s[25];
};
bool cmp(Stu x,Stu y)
{
	return x.name<y.name;
}
int main()
{
	Stu a[40000];
	int n,m;
    cin>>n>>m;
    int b[2500] = {0};
    for(int i=0;i<n;i++)
    {
        cin>>a[i].name>>a[i].x;
        for(int j= 0;j<a[i].x;j++)
        {
            cin>>a[i].s[j];
            b[a[i].s[j]]++;
        }
    }
    sort(a,a+n,cmp);
    for(int i=1;i<=m;i++)
    {
        cout<<i<<" "<<b[i]<<endl;
        for(int j = 0;j<n;j++)
        {
        	for(int k = 0;k<a[j].x;k++)
			{
				if(a[j].s[k]==i)
				{
					cout<<a[j].name<<endl;
				}	
			} 
		}
    }
	return 0;
}

宿舍大佬帮写的代码:

还没研究透,有兴趣的伙伴们可以看一下:
AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
vector<string> st[maxn];
pair<string,vector<int>> stu[maxn];
int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int n,k;
    cin>>n>>k;
    string name;
    for(int i=1;i<=n;i++){
        cin>>stu[i].first;
        int nn;
        cin>>nn;
        while(nn--){
            int x;
            cin>>x;
            stu[i].second.push_back(x);
        }
    }
    sort(stu+1,stu+1+n);
    for(int i=1;i<=n;i++){
        for(auto ch:stu[i].second){
            st[ch].push_back(stu[i].first);
        }
    }
    for(int i=1;i<=k;i++){
        cout<<i<<" "<<st[i].size()<<"\n";
        for(auto ch:st[i]){
            cout<<ch<<"\n";
        }
    }
    return 0;
}

好了,就到这里了,欢迎大家和我进行讨论,虽然自己是个菜菜!
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CX__CS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值