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值比原值大,就更新原值,如果与原值相等,就对路径的条数做处理即可。此题比较好的一点是要用到高精度,需要自己去封装一个类,重载一下加号和等号就行了。