数据结构第七次实验

本文探讨了四个信息技术问题:7-1序列调度利用栈模拟操作,7-2最大最小差通过堆优化,7-3二叉树最短路径长度的递归遍历,以及7-4生产优化中的关键方案计数。博主谷方明提供了详细解释和代码实现,适合理解算法与优化策略。
摘要由CSDN通过智能技术生成

7-1 序列调度 (100 分)

有一个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

作者

谷方明

单位

吉林大学

代码长度限制

16 KB

时间限制

100 ms

内存限制

10 MB

#include <bits/stdc++.h>
using namespace std;
stack<int>s;
int b[10010];
int t;
int c;
int main(){
 scanf("%d%d",&t,&c);
 int n;
 int tt=0;
 int mark=0;
 for(int i=0;i<t;i++){
 scanf("%d",&n);
 tt=1;
 while(!s.empty()) s.pop();
 mark=0;
 for(int j=0;j<n;j++)
 scanf("%d",&b[j]);

 for(int j=0;j<n;j++){
 if(!s.empty()&&s.top()==b[j]){
 s.pop();
 continue;
 }
if(b[j]<tt){
 if(b[j]!=s.top()){
      mark=1; break;
 }
 s.pop();
 }
for(;tt<=n;tt++){
     s.push(tt);
    if(tt==b[j]){
     tt++; break;
 }
 }
if(s.size()>c) mark=1;
 s.pop();
 if(mark==1) break;
 }
 if(!s.empty()) mark=1;
 if(mark==1) printf("No\n");
 else printf("Yes\n");
 }
}

我的思路:本题是一个栈模拟,关键是要弄明白弹栈压栈的整个过程,如果序列中的数在栈中就把它弹出,同时要注意栈的容量和栈的性质,要按照递增序列去压栈。

 

 

7-2 最大最小差 (100 分)

对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

作者

谷方明

单位

吉林大学

代码长度限制

16 KB

时间限制

100 ms

内存限制

#include<bits/stdc++.h>
using namespace std;
#define ll long long
priority_queue<ll>q1;
priority_queue<ll,vector<ll>,greater<ll>>q2;
int main(){
ll n,m,x1,x2;
scanf("%lld",&n);
for(ll i=1;i<=n;i++){
    scanf("%lld",&m);
    q1.push(m);
    q2.push(m);
}
while(q1.size()!=1&&q2.size()!=1){     //q1是大根堆,q2是小根堆。
    x1=q1.top(); q1.pop();
    x2=q1.top(); q1.pop();
    q1.push(x1*x2+1);
    x1=q2.top(); q2.pop();
    x2=q2.top(); q2.pop();
    q2.push(x1*x2+1);
}
printf("%lld",q2.top()-q1.top());
}

我的思路:这道题比较简单,很容易想到用堆去优化,于是就想到了priority_queue,构建一个大根堆一个小根堆,大根堆最后保留的是最小值,小根堆最后保留的是最大值。

 

 

7-3 二叉树最短路径长度 (100 分)

给定一棵二叉树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

作者

谷方明

单位

吉林大学

代码长度限制

16 KB

时间限制

1000 ms

内存限制

10

 

#include<bits/stdc++.h>
using namespace std;
int weight[20010];
int s[20010];
int preorder[20010];
int inorder[20010];
struct bintree{
int data;
struct bintree* left;
struct bintree* right;
};
void Create_bintree(bintree* &t,int* preorder,int* inorder,int n){
int i,k;
if(n==0){
    t=NULL;
    return;
      }
for(i=0;i<n;i++)
    if(inorder[i]==preorder[0])
        break;
k=i;
t=new bintree;
t->data=inorder[k];
Create_bintree(t->left,preorder+1,inorder,k);
Create_bintree(t->right,preorder+k+1,inorder+k+1,n-k-1);
}
void depth_order(bintree* t){
if(t->left){
    s[t->left->data]=s[t->data]+weight[t->left->data];
    depth_order(t->left);
}
if(t->right){
    s[t->right->data]=s[t->data]+weight[t->right->data];
    depth_order(t->right);
}
return;
}
int main(){
    int n,i;
    bintree* t;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&preorder[i]);
    for(i=0;i<n;i++)
        scanf("%d",&inorder[i]);
    for(i=1;i<=n;i++)
        scanf("%d",&weight[i]);
    Create_bintree(t,preorder,inorder,n);
    s[t->data]=weight[t->data];
    depth_order(t);
    for(i=1;i<n;i++)
        printf("%d ",s[i]);
    printf("%d",s[n]);
}

 

我的思路:此题属于模板题,就是先用递归创建出树,然后用递归深搜这棵树,此题思维方式上不难,难的是对这个思维的理解和运用。

 

7-4 方案计数 (100 分)

组装一个产品需要 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

作者

谷方明

单位

吉林大学

代码长度限制

16 KB

时间限制

200 ms

内存限制

#include<bits/stdc++.h>
using namespace std;
struct edge{
int Veradj;
int cost;
struct edge* link;
};
struct Vertex{
edge* adjacent;
}head[10010];
int weight[10010];
int Time[10010];
class Gao_jingdu{
public:
    int b[110];
    int len;
    Gao_jingdu(){
    len=0; b[110]={0};
    }
    Gao_jingdu operator +(const Gao_jingdu &x){
    Gao_jingdu y;
    int j;
    y.len=max(x.len,len);
    for( j=0;j<y.len;j++)
        y.b[j]=b[j]+x.b[j];
    for( j=0;j<y.len;j++){
        y.b[j+1]+=(y.b[j]/10);
        y.b[j]=y.b[j]%10;
    }
    int q=y.b[y.len];
    while(q){
        y.b[y.len++]=q%10; q/=10;
    }
    return y;
    }

    Gao_jingdu& operator=(const Gao_jingdu& a){
    for(int i=0;i<110;i++)
        b[i]=a.b[i];
    len=a.len;
    return *this;
    }
    void show(){
    for(int i=len-1;i>=0;--i)
    cout<<b[i];
    }
};
Gao_jingdu s[10010];
int main(){
int n,m,i,j,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
    scanf("%d",&weight[i]);
for(i=1;i<=n;i++)
    head[i].adjacent=NULL;
for(i=1;i<=m;i++){
    scanf("%d%d",&x,&y);
       edge* p=head[x].adjacent;
       edge* q=new edge;
       q->Veradj=y;
       q->cost=weight[y];
       q->link=p;
       head[x].adjacent=q;
}
for(i=1;i<=n;i++)
    Time[i]=0;
queue<int>qq;
int Count[10010];
for(i=1;i<=n;i++)
    Count[i]=0;
for(i=1;i<=n;i++)
    for(edge* p=head[i].adjacent;p;p=p->link)
    Count[p->Veradj]++;
for(i=1;i<=n;i++)
    if(Count[i]==0){
        qq.push(i);
        Time[i]=weight[i];
        s[i].b[0]=1;
        s[i].len=1;
    }
for(i=1;i<=n;i++){
    if(qq.empty()){
          cout<<"0";
          return 0;
    }
    j=qq.front();
          qq.pop();
          for(edge* p=head[j].adjacent;p;p=p->link){
            int  k=p->Veradj;
            Count[k]--;
            if(Count[k]==0)
                qq.push(k);
            if(Time[j]+p->cost>Time[k]){
                Time[k]=Time[j]+p->cost;
                s[k]=s[j];
            }
           else  if(Time[j]+p->cost==Time[k])
                s[k]=s[j]+s[k];
          }
}
Gao_jingdu sum;
int maxn=-1;
for(i=1;i<=n;i++){
    if(Time[i]>maxn){
        maxn=Time[i];
        sum=s[i];
    }
   else  if(Time[i]==maxn)
        sum=sum+s[i];
    }
printf("%d\n",maxn);
sum.show();
}



我的思路:这个题我觉得没必要构建虚源点去做,直接用拓扑排序即可,如果time值比原值大,就更新原值,如果与原值相等,就对路径的条数做处理即可。此题比较好的一点是要用到高精度,需要自己去封装一个类,重载一下加号和等号就行了。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值