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
思路:一个一个读入,当读入的数比当前栈顶的数大时,就继续压栈,并记录栈中的元素数,栈溢出直接退出。当读入的数比栈顶的数小或等于时,就弾栈,如果弹出的数不是这个元素,退出程序。直到栈空。
代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=1e9+7;
int t,c,n;
int a[10002];
int main()
{
cin>>t>>c;
while(t--)
{
int x,tmp=1,countt=0,flag=1;
cin>>n;
for(int j=0;j<n;j++)
{
scanf("%d",&x);
while(tmp<=x) a[countt++]=tmp,tmp++;
if(countt>c) flag=0;
if(x==a[countt-1]) countt--;
else flag=0;
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
//system("PAYSE");
}
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
思路:每次选两个小的数,得到的是最大值,每次选两个大的数,得到的是最小值。
代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=1e9+7;
priority_queue<ll,vector<ll> ,greater<ll> >qq;
priority_queue<ll,vector<ll> ,less<ll> >q;
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
ll x;
cin>>x;
q.push(x);
qq.push(x);
}
for(int i=1;i<n;i++)
{
ll a=q.top();q.pop();
ll b=q.top();q.pop();
ll now=a*b+1;
q.push(now);
}
int minn=q.top();
for(int i=1;i<n;i++)
{
ll a=qq.top();qq.pop();
ll b=qq.top();qq.pop();
ll now=a*b+1;
qq.push(now);
}
int maxx=qq.top();
printf("%d",maxx-minn);
}
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
思路:根据先根序列和中根序列可以唯一确定一棵二叉树,这样就可以通过递归实现建树操作,思想:每次选择当前范围先根序列中的第一个元素作为根节点,在从当前范围的中根序列中找到根节点的编号,这样中根序列中根节点标号左边的元素就是左子树,右边的标号就是右子树。
至于找最小的路径,由于每个子节点都有唯一的一个父节点,所以根节点到每个子节点的距离都是唯一确定的,只要求出距离就是最小距离。所以这里可以使用各种遍历的方式来求最短路径。
代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=1e9+7;
int n;
struct Node
{
int hao;
int zhi;
Node*left,*right;
Node(int x,int y):hao(x),zhi(y){}
};
queue<Node*>q;
int a[50001],b[50001],c[50001],endd[50001];
Node* build(int x,int y,int ii,int jj)
{
if(ii>jj) return 0;
Node* sja=new Node(a[ii],c[a[ii]]);
int k=x;
while(b[k]!=a[ii]) k++;
sja->left=build(x,k-1,ii+1,ii+k-x);
sja->right=build(k+1,y,ii+k+1-x,jj);
return sja;
}
void order()
{
while(!q.empty())
{
Node*p=q.front();
q.pop();
if(p->left)
{
p->left->zhi=p->left->zhi+p->zhi;
endd[p->left->hao]=p->left->zhi;
q.push(p->left);
}
if(p->right)
{
p->right->zhi=p->right->zhi+p->zhi;
endd[p->right->hao]=p->right->zhi;
q.push(p->right);
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
Node*phead=build(1,n,1,n);
q.push(phead);
order();
printf("%d",c[1]);
for(int i=2;i<=n;i++) printf(" %d",endd[i]);
}
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
思路:求关键路径,我更习惯对AOE网进行操作,所以我引入了虚源虚汇,把AOV网转换为AOE网,之后拓扑排序求出一个拓扑序列和最早开始时间,再逆拓扑序求出最迟开始时间。找出关键路径上的点,在使用乘法原理算出答案(使用了高精度乘法)
代码实现:
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
const int INF = 1e8+9;
const int maxn = 2e4+5;
vector<pair<int,int> >vec[maxn];
queue<int>q,qq;
int n,m;
int tim[maxn],indeg[maxn];
int vl[maxn];
int ve[maxn];
int shunxu[maxn],top;
int bj[maxn];
int endd[120]={1,1};
void multi(int x)
{
int i;
for(i=1;i<=101;i++)
{
endd[i]*=x;
}
int c=0;
for(i=1;i<=101;i++)
{
endd[i]+=c;
c=endd[i]/10;
endd[i]%=10;
}
}
int bfs()
{
qq.push(0);
bj[0]=1;
int flag=-1,ans=0;
while(!qq.empty())
{
int now=qq.front();qq.pop();
if(now==flag)
{
multi(ans);
ans=0;
flag=-1;
}
ans++;
for(int i=0;i<vec[now].size();i++)
{
int x=vec[now][i].first;
if(!bj[x]&&vl[x]==ve[x]&&x!=n+1) qq.push(x),bj[x]=1;
if(flag==-1&&x!=n+1) flag=x;
}
}
}
int main()
{
cin>>n>>m;
int x,y;
for(int i=1;i<=n;i++) scanf("%d",&tim[i]);
if(m==0)
{
int da=0,cou=1;
for(int i=1;i<=n;i++)
{
if(tim[i]>da) {da=tim[i];cou=1;}
else if(da==tim[i]) cou++;
}
printf("%d\n",da);
printf("%d\n",cou);
exit(0);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
vec[x].pb(mp(y,tim[x]));
indeg[y]++;
}
for(int i=1;i<=n;i++)
{
if(!indeg[i])
{
vec[0].pb(mp(i,0));
indeg[i]++;
}
else if(!vec[i].size())
{
vec[i].pb(mp(n+1,tim[i]));
indeg[n+1]++;
}
}
q.push(0);
for(int i=0,k=0;i<=n+1;i++)
{
if(q.empty())
{
printf("%d",0);
exit(0);
}
int now=q.front();q.pop();
shunxu[k++]=now;
for(int j=0;j<vec[now].size();j++)
{
int x=vec[now][j].first;
indeg[x]--;
if(!indeg[x]) q.push(x);
}
}
for(int i=0;i<=n;i++)
{
int s=shunxu[i];
for(int j=0;j<vec[s].size();j++)
{
int x=vec[s][j].first;
if(ve[x]<ve[s]+vec[s][j].second)
{
ve[x]=ve[s]+vec[s][j].second;
}
}
}
vl[n+1]=ve[n+1];
for(int i=0;i<=n;i++) vl[i]=INF;
for(int i=n;i>=1;i--)
{
int s=shunxu[i];
for(int j=0;j<vec[s].size();j++)
{
int x=vec[s][j].first;
int y=vec[s][j].second;
if(vl[x]-y<vl[s])
{
vl[s]=vl[x]-y;
}
}
}
bfs();
printf("%d\n",ve[n+1]);
int i;
for(i=119;!endd[i];i--);
for(;i>=1;i--) printf("%d",endd[i]);
}