Bootstrap

SDUT数据结构与算法第四次机测

7-1 统计工龄

给定公司 n 名员工的工龄,要求按工龄增序输出每个工龄段有多少员工。

输入格式:

输入首先给出正整数 n(≤105),即员工总人数;随后给出 n 个整数,即每个员工的工龄,范围在 [0, 50]。

输出格式:

按工龄的递增顺序输出每个工龄的员工个数,格式为:“工龄:人数”。每项占一行。如果人数为 0 则不输出该项。

输入样例:

8
10 2 0 5 7 2 5 2

输出样例:

0:1
2:3
5:2
7:1
10:1
#include<stdio.h>
int main()
{
    int age[10001]={0};
    int n;
    int i;
    scanf("%d",&n);
    int a;
    for(i=0;i<n;i++)
    {
        scanf("%d",&a);
        age[a]++;
    }
    for(i=0;i<51;i++)
    {
        if(age[i]!=0)
        {
            printf("%d:%d\n",i,age[i]);
        }
    }
    return 0;
}

7-2 公路村村通

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数 n(≤1000)和候选道路数目 m(≤3n);随后的 m 行对应 m 条道路,每行给出 3 个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从 1 到 n 编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出 −1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12
#include<bits/stdc++.h>
using namespace std;
int f[1001];
struct road
{
    int x,y,cost;
}s[3001];
int cmp(road a,road b)
{
    return a.cost<b.cost;
}
int find(int x)
{
    if(f[x]==x)
        return x;
    else
        return f[x]=find(f[x]);
}
int merg(int x,int y)
{
    if(find(x)!=find(y))
    {
        f[find(x)]=find(y);
        return 1;
    }
    return 0;
}
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<n;i++)
    {
        f[i]=i;
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d %d %d",&s[i].x,&s[i].y,&s[i].cost);
    }
    sort(s,s+m,cmp);
    int sum=0;
    for(int i=0;i<m&&n>1;i++)
    {
        if(merg(s[i].x,s[i].y)==1)
        {
            sum=sum+s[i].cost;
            n--;
        }
    }
    if(n==1)
        printf("%d",sum);
    else
        printf("-1");
    return 0;
}

7-3 旅游规划

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:

输入说明:输入数据的第 1 行给出 4 个正整数 n、m、s、d,其中 n(2≤n≤500)是城市的个数,顺便假设城市的编号为 0~(n−1);m 是高速公路的条数;s 是出发地的城市编号;d 是目的地的城市编号。随后的 m 行中,每行给出一条高速公路的信息,分别是:城市 1、城市 2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过 500。输入保证解的存在。

输出格式:

在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40
#include<bits/stdc++.h>
using namespace std;
int a[500][500];
int b[500][500];
int n,m,s,d;
int main()
{
    scanf("%d %d %d %d",&n,&m,&s,&d);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            a[i][j]=b[i][j]=10086;
        }
    }
    for(int i=0;i<m;i++)
    {
        int x,y,length,money;
        scanf("%d %d %d %d",&x,&y,&length,&money);
        a[x][y]=a[y][x]=length;
        b[x][y]=b[y][x]=money;
    }
    for(int k=0;k<n;k++)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(a[i][j]>a[i][k]+a[k][j]||a[i][j]==a[i][k]+a[k][j]&&b[i][j]>b[i][k]+b[k][j])
                {
                    a[i][j]=a[i][k]+a[k][j];
                    b[i][j]=b[i][k]+b[k][j];
                }
            }
        }
    }
    printf("%d %d",a[s][d],b[s][d]);
    return 0;
}

 7-4 任务调度的合理性

假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。

比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和 C 程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如 C 程序设计和数据结构两门课,必须先学习前者。

但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务 a 依赖于子任务 b,子任务 b 依赖于子任务 c,子任务 c 又依赖于子任务 a”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。你现在的工作是写程序判定任何一个给定的任务调度是否可行。

输入格式:

输入说明:输入第一行给出子任务数 n(≤100),子任务按 1~n 编号。随后 n 行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数 k,随后给出 k 个子任务编号,整数之间都用空格分隔。

输出格式:

如果方案可行,则输出 1,否则输出 0。

输入样例1:

12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7

输出样例1:

1

输入样例2:

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

输出样例2:

0
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int f[105][105];
int degree[105] , book[105];
int main(){
    int n , k;
    int temp;
    cin>>n;
    for(int i = 1 ; i <= n ; i++){
        cin>>k;
        for(int j = 1 ; j <= k ; j++){
            cin>>temp;
            f[temp][i] = 1;
        }
        degree[i] = k;
    }
    for(int i = 1 ; i <= n ; i++){
        int ans , flag = -1;
        for(int j = 1 ; j <= n ; j++){
            if(degree[j] == 0 && book[j] == 0){
                flag = 1;
                ans = j;
                book[j] = 1;
                break;
            }
        }
        if(flag == 1){
            for(int j = 1 ; j <= n ; j++){
                if(f[ans][j] == 1){
                    f[ans][j] = 0;
                    degree[j]--;
                }
            }
        }
        else break;
    }
    int flag = 1;
    for(int i = 1 ; i <= n ; i++){
        if(degree[i] != 0){
            flag = 0;
            break;
        }
    }
    if(flag) cout<<"1";
    else cout<<"0";
}
 

 7-5 这是二叉搜索树吗?

一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,

  • 其左子树中所有结点的键值小于该结点的键值;
  • 其右子树中所有结点的键值大于等于该结点的键值;
  • 其左右子树都是二叉搜索树。

所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。

给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。

输入格式:

输入的第一行给出正整数 N(≤1000)。随后一行给出 N 个整数键值,其间以空格分隔。

输出格式:

如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出 YES ,然后在下一行输出该树后序遍历的结果。数字间有 1 个空格,一行的首尾不得有多余空格。若答案是否,则输出 NO

输入样例 1:

7
8 6 5 7 10 8 11

输出样例 1:

YES
5 7 6 8 11 10 8

输入样例 2:

7
8 10 11 8 6 7 5

输出样例 2:

YES
11 8 10 7 5 6 8

输入样例 3:

7
8 6 8 5 10 9 11

输出样例 3:

NO
#include<bits/stdc++.h>
using namespace std;
int num[1010],n,pre[1010];
int flag=1;
void dfs(int l,int r)
{
    if(l>r)
        return;
    int i=l+1,j=r;
    if(flag)
    {
        while(i<=r&&pre[i]<pre[l])
            i++;
        while(j>l&&pre[j]>=pre[l])
            j--;
    }
    else
    {
        while(i<=r&&pre[i]>=pre[l])
            i++;
        while(j>l&&pre[j]<pre[l])
            j--;
    }
    dfs(l+1,j);
    dfs(i,r);
    num[++num[0]]=pre[l];
}
int main()
{
    cin>>n;
    int i,j,k;
    for(i=1;i<=n;i++)
    {
        cin>>pre[i];
    }
        dfs(1,n);
        if(num[0]!=n)
        {
            flag=0;
            num[0]=0;
            dfs(1,n);
        }
        if(num[0]!=n)
            cout<<"NO";
        else
        {
            cout<<"YES\n"<<num[1];
            for(i=2;i<=num[0];i++)
                cout<<" "<<num[i];
        }
    return 0;
}

 7-6 二分查找

输入n值(1<=n<=1000)、n个非降序排列的整数以及要查找的数x,使用二分查找算法查找x,输出x所在的下标(0~n-1)及比较次数。若x不存在,输出-1和比较次数。

输入格式:

输入共三行:
第一行是n值;
第二行是n个整数;
第三行是x值。

输出格式:

输出x所在的下标(0~n-1)及比较次数。若x不存在,输出-1和比较次数。

输入样例:

4
1 2 3 4
1

输出样例:

0
2
#include<bits/stdc++.h>
using namespace std;
int a[1005];
int main(){
    int n,i,x,y=0,l,r,k=0,mid;
    cin>>n;
    for(i=0;i<n;i++)cin>>a[i];
    cin>>x;
     for(i=0;i<n;i++){
         if(x==a[i]){k=1;break;}
     }
    l=0;r=n-1;
    while(l<=r){
         y++;
        mid=(l+r)/2;
        if(a[mid]>x)r=mid-1;
        else l=mid+1;
    }
    if(k==1) cout<<mid<<endl<<y;
    else cout<<"-1\n"<<y;
    return 0;
} 
;