数据结构第七次上机实验报告

7-1 序列调度 

有一个N个数的序列A:1,2,……,N。有一个后进先出容器D,容器的容量为C。如果给出一个由1到N组成的序列,那么可否由A使用容器D的插入和删除操作得到。

输入格式:

第1行,2个整数T和C,空格分隔,分别表示询问的组数和容器的容量,1≤T≤10,1≤C≤N。

第2到T+1行,每行的第1个整数N,表示序列的元素数,1≤N≤10000。接下来N个整数,表示询问的序列。

输出格式:

T行。若第i组的序列能得到,第i行输出Yes;否则,第i行输出No,1≤i≤T。

输入样例:

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

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

输出样例:

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

No
Yes

分析:

模拟一个栈,将序列A一次入栈,判断输入序列是否和栈顶元素一一相等,相等即出栈。如果最后栈空则输出Yes,否则输出No。

完整代码:

#include<bits/stdc++.h>
#include<queue>
#include<stack>
using namespace std;

const int MAX=10005;

typedef long long ll;
int T,C;
int n,res;
int a[MAX],b[MAX];
stack<int>q;
int main()
{
    scanf("%d %d",&T,&C);
    for(int i=1;i<=MAX;i++)
        a[i]=i;
    while(T--)
    {
        res=1;
        scanf("%d",&n);
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        for(int i=1;i<=n;i++)
        {
             if(q.size()<C)
                q.push(a[i]);
             else
                break;
             while(q.top()==b[res])
             {
                 q.pop();
                 res++;
                 if(q.empty())
                    break;
             }
        }
        if(!q.empty())
            printf("No\n");
        else
            printf("Yes\n");
    }
    return 0;
}

7-2 最大最小差 

对n 个正整数,进行如下操作:每一次删去其中两个数 a 和 b,然后加入一个新数:a*b+1,如此下去直到 只剩下一个数。所有按这种操作方式最后得到的数中,最大的为max,最小的为min,计算max-min。

输入格式:

第1行:n,数列元素的个数,1<=n<=16。

第2行:n 个用空格隔开的数x,x<=10。

输出格式:

1行,所求max-min。

输入样例:

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

3
2 4 3

输出样例:

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

2

分析:

运用单调队列,每次选队列中最小的两个数做运算,求min。每次选队列中最大的两个数做运算,求max,最后相减,注意数据范围,用long long,否则样例不能全部通过。

完整代码:

#include<bits/stdc++.h>
#include<queue>
using namespace std;

typedef long long ll;
int n;
ll maxx,minn;
priority_queue<ll,vector<ll>,greater<ll>>q;
priority_queue<ll,vector<ll>,less<ll>>p;
ll res;
int main()
{
    scanf("%d",&n);
    ll L;
    if(n==1)
    {
        printf("0");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&L);
        q.push(L);
        p.push(L);
    }
    while(q.size()>1)
    {
        ll a=q.top();
        q.pop();
        ll b=q.top();
        q.pop();
        q.push(a*b+1);
    }
    while(p.size()>1)
    {
        ll a=p.top();
        p.pop();
        ll b=p.top();
        p.pop();
        p.push(a*b+1);
    }
    maxx=q.top();
    minn=p.top();
    printf("%lld\n",maxx-minn);
    return 0;
}

7-3 二叉树最短路径长度

给定一棵二叉树T,每个结点赋一个权值。计算从根结点到所有结点的最短路径长度。路径长度定义为:路径上的每个顶点的权值和。

输入格式:

第1行,1个整数n,表示二叉树T的结点数,结点编号1..n,1≤n≤20000。

第2行,n个整数,空格分隔,表示T的先根序列,序列中结点用编号表示。

第3行,n个整数,空格分隔,表示T的中根序列,序列中结点用编号表示。

第4行,n个整数Wi,空格分隔,表示T中结点的权值,-10000≤Wi≤10000,1≤i≤n。

输出格式:

1行,n个整数,表示根结点到其它所有结点的最短路径长度。

输入样例:

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

4
1 2 4 3
4 2 1 3
1 -1 2 3

输出样例:

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

1 0 3 3

分析:

1、运用先跟序列和中跟序列建树。

2、运用dfs求根节点到每个节点的最短路径。

完整代码:

#include<bits/stdc++.h>
#include<queue>
#include<stack>
using namespace std;

const int MAX=20005;

typedef long long ll;
int pre[MAX];
int mid[MAX];
int value[MAX];
vector<int>tree[5*MAX];
int visit[MAX];
int n;
void treecreate(int a1,int a2,int b1,int b2,int root)
{
    if(a1>a2||b1>b2)return;
    else
    {
        int s=pre[a1];
        for(int i=b1;i<=b2;i++)
        {
            if(mid[i]==s)
            {
                s=i;
                break;
            }
        }
        tree[mid[root]].push_back(mid[s]);
        treecreate(a1+1,a2+s-b1,b1,s-1,s);
        treecreate(a1+s-b1+1,a2,s+1,b2,s);
    }
}
void dfs(int node)
{
    if(visit[node])return;
    else
    {
        visit[node]=1;
        for(int i=0;i<tree[node].size();i++)
        {
            int s=tree[node][i];
            value[s]=value[s]+value[node];
            dfs(s);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&pre[i]);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&mid[i]);
    }
    treecreate(1,n,1,n,0);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&value[i]);
    }
    dfs(pre[1]);
    for(int i=1;i<=n;i++)
    {
        printf("%d",value[i]);
        printf("%c",i!=n ? ' ':'\n');
    }
    return 0;
}

7-4 方案计数

组装一个产品需要 n 个零件。生产每个零件都需花费一定的时间。零件的生产可以并行进行。有些零件的生产有先后关系,只有一个零件的之前的所有零件都生产完毕,才能开始生产这个零件。如何合理安排工序,才能在最少的时间内完成所有零件的生产。在保证最少时间情况下,关键方案有多少种,关键方案是指从生产开始时间到结束时间的一个零件生产序列,序列中相邻两个零件的关系属于事先给出的零件间先后关系的集合,序列中的每一个零件的生产都不能延期。

输入格式:

第1行,2个整数n和m,用空格分隔,分别表示零件数和关系数,零件编号1..n,1≤n≤10000, 0≤m≤100000 。

第2行,n个整数Ti,用空格分隔,表示零件i的生产时间,1≤i≤n,1≤Ti≤100 。

第3到m+2行,每行两个整数i和j,用空格分隔,表示零件i要在零件j之前生产。

输出格式:

第1行,1个整数,完成生产的最少时间。

第2行,1个整数,关键方案数,最多100位。

如果生产不能完成,只输出1行,包含1个整数0.

输入样例:

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

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

输出样例:

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

4
2

分析:

1.拓扑排序求关键路径长度。

2.正向遍历和逆向遍历确定关键活动。

3.分层求出每一层有多少种方案,利用乘法原理求出关键方案总数,因为关键方案数最多可能有100位,因而要用到高精度计算。

完整代码:

#include<bits/stdc++.h>
#include<queue>
#include<stack>
using namespace std;

const int MAX=10010;

typedef long long ll;

vector<vector<int>>G,H;
vector<int>in,out;
queue<int>q,p;
vector<int>lenth;
int a[110];
int b[MAX],c[MAX];
int sum,ans,mul;
int flag=-1;
int n,m;
void ss(int k)
{
   for(int i=1;i<=a[0];i++)
       a[i]*=k;
   for(int i=1;i<=a[0];i++)
    {
       a[i+1]+=a[i]/10;
       a[i]%=10;
    }
   while(a[a[0]+1]>0)
   {
       a[0]++;
       a[a[0]+1]=a[a[0]]/10;
       a[a[0]]=a[a[0]]%10;
   }
}
int main()
{
    a[0]=1;
    a[1]=1;
    scanf("%d %d",&n,&m);
    G=vector<vector<int>>(n+1);
    H=vector<vector<int>>(n+1);
    in=vector<int>(n+1);
    out=vector<int>(n+1);
    lenth=vector<int>(n+1);
    for (int i=1;i<=n;i++)
    {
       scanf("%d",&lenth[i]);
    }
    for(int i=1;i<=m;i++)
    {
       int x,y;
       scanf("%d %d",&x,&y);
       G[y].push_back(x);
       H[x].push_back(y);
       in[x]++;
       out[y]++;
     }
    for(int i=1;i<=n;i++)
       if(!in[i])
       {
          q.push(i);
          b[i]=lenth[i];
       }
    while(!q.empty())
    {
       int s=q.front();
       q.pop();
       sum++;
    for(int i=0;i<G[s].size();i++)
     {
       int nex=G[s][i];
       b[nex]=max(b[nex],b[s]+lenth[nex]);
       in[nex]--;
       if(in[nex]==0)
          q.push(nex);
      }
    }
    for(int i=1;i<=n;i++)
        ans=max(ans,b[i]);
    for(int i=1;i<=n;i++)
        if (!out[i])
         {
             p.push(i);
             c[i]=lenth[i];
         }
    while(!p.empty())
    {
        int s=p.front();
        if(s==flag)
        {
           ss(mul);
           mul=0;
           flag=-1;
        }
     mul++;
     p.pop();
    for(int i=0;i<H[s].size();i++)
    {
         int nex=H[s][i];
         c[nex]=max(c[nex],c[s]+lenth[nex]);
         out[nex]--;
         if(out[nex]==0&&b[nex]+c[nex]-lenth[nex]==ans)
              p.push(nex);
         if(flag==-1)
            flag=nex;
     }
     }
    if(m==0)
    {
       a[1]--;
       for(int i=1;i<=n;i++)
       {
           if(b[i]+c[i]-lenth[i]==ans)
               a[1]++;
       }
    }
     if(sum==n)
     {
          printf("%d\n",ans);
          for(int i=a[0];i>=1;i--)
              printf("%d",a[i]);
      }
      else
           printf("0");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值