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");
}