有一个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[10001]
存储要得到的序列,使用一个栈stack
模拟1~n的入栈和出栈。
如果,栈顶元素等于要得到的序列的当前首元素,则弹栈s.pop();
,且所要求序列后移一位sum++;
。
直到s.size()>C
或sum==n
分别输出No或Yes。
#include
#include
using namespace std;
stack<int> s;
int a[10001];
int main()
{
int T,C;
cin>>T>>C;
int n;
for(int i=1;i<=T;i++)
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int sum=0;//已经得到的数字的总个数
int num=1;//计数
while(1)
{
while(sum!=n&&s.empty()!=1&&s.top()==a[sum])
{
s.pop();
sum++;
}
if(s.size()>C)
{
cout<<"No"<<endl;
break;
}else s.push(num++);
if(sum==n)
{
cout<<"Yes"<<endl;
break;
}
}
}
}
对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
这题主要是得找到一个规律,取两小相乘+1,重复执行,会得到max。同理,取两大相乘+1,重复执行,会得到min。
这里,我们可以使用优先级队列进行取两小和两大的操作。
priority_queue<int, vector<int>, less<int>> q1;
priority_queue<int, vector<int>, greater<int>> q2;
其中第一个参数是容器中数据类型(int),第二个参数是容器适配器所依赖的容器类型(vector),第三个参数则是一个用于比较的一元谓词。
主体操作,就是如下代码:出队a,b和入队ab+1。
a = q1.top();
q1.pop();
b = q1.top();
q1.pop();
q1.push(a * b + 1);
至于证明留给读者自行思考,我也不会
#include
#include
#include
using namespace std;
priority_queue<int, vector<int>, less<int>> q1;
priority_queue<int, vector<int>, greater<int>> q2;
int main()
{
int n;
cin >> n;
int x;
for (int i = 1; i <= n; i++)
{
cin >> x;
q1.push(x);
q2.push(x);
}
int a, b;
for (int i = 1; i <= n-1; i++)
{
a = q1.top();
q1.pop();
b = q1.top();
q1.pop();
q1.push(a * b + 1);
a = q2.top();
q2.pop();
b = q2.top();
q2.pop();
q2.push(a * b + 1);
}
cout << q2.top() - q1.top();
}
给定一棵二叉树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
首先思考第一个问题,如何使用先序和中序构建二叉树。
举个栗子:
先根序ABCDEF
中根序BDCAFE
先根序中A为根,在中根序中找到A则A的左子树中根序为BDC,右子树中根序为FE,再回到先根序BCDEF找此时的左子树先根序为BCD,右子树先根序为EF。显然,这可以用递归来解决,参考代码如下:
void creat(Tree& T,int* preorder,int* inorder,int now_n)
{
if(now_n==0)
{
T=NULL;
return ;
}//递归出口
int k,i;//找位置
T = new TreeNode;
T->data=preorder[0];
T->weight=value[preorder[0]];
// cout<<*preorder<<" ";
for(i = 0; i<now_n; i++)//找位置
if(inorder[i] == preorder[0])
break;
k=i;
creat(T->left,preorder+1,inorder,k);
//递归调用本算法创建左子树
creat(T->right,preorder+k+1,inorder+k+1,now_n-k-1);
//递归调用本算法创建右子树
}
跟打印每条路径的思路差不多,只不过不是打印,而是在遍历时存储并相加每个点的权值得到sum。
void printpath(Tree& T,int sum) {
//二叉树中从每个叶子结点到根结点的路径
//cout<
if (T != NULL) {
int s=sum+T->weight;//将当前结点权值放入路径中
ret[T->data]=s;
if (T->left == NULL && T->right == NULL) {//叶子结点
} else {
printpath(T->left,s);
printpath(T->right,s);
}
}
}
#include
using namespace std;
typedef struct node {
int data;
struct node* left;
struct node* right;
int weight;
} TreeNode, * Tree;
int n;
int preorder[20001];
int inorder[20001];
int value[20001];
int ret[20001];
void creat(Tree& T,int* preorder,int* inorder,int now_n)
{
if(now_n==0)
{
T=NULL;
return ;
}//递归出口
int k,i;//找位置
T = new TreeNode;
T->data=preorder[0];
T->weight=value[preorder[0]];
// cout<<*preorder<<" ";
for(i = 0; i<now_n; i++)//找位置
if(inorder[i] == preorder[0])
break;
k=i;
creat(T->left,preorder+1,inorder,k);
//递归调用本算法创建左子树
creat(T->right,preorder+k+1,inorder+k+1,now_n-k-1);
//递归调用本算法创建右子树
}
void printpath(Tree& T,int sum) {
//二叉树中从每个叶子结点到根结点的路径
//cout<
if (T != NULL) {
int s=sum+T->weight;//将当前结点权值放入路径中
ret[T->data]=s;
if (T->left == NULL && T->right == NULL) {//叶子结点
} else {
printpath(T->left,s);
printpath(T->right,s);
}
}
}
int main() {
cin>>n;
for(int i=0; i<n; i++) cin>>preorder[i];
for(int i=0; i<n; i++) cin>>inorder[i];
for(int i=1; i<=n; i++) cin>>value[i];
Tree T;
creat(T,preorder,inorder,n);
int sum=0;
printpath(T,sum);
//ret[T->data]=T->weight;
for(int i=1;i<n;i++) cout<<ret[i]<<" ";
cout<<ret[n]<<endl;
}
组装一个产品需要 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
题目的思路不难,但写起来,却烦的很。由题意不难发现,是一道关于关键路径的题。求关键路径不难,难在求关键方案的数目。还有一点就是,关键方案数是100位数,故还得使用高精度的算法。
首先,我们得先运用虚源虚汇的方法将点权转化为边权。(就是设个虚源,边权为0,并把每个点的点权后移到对应边上即可)
至于拓扑排序如何进行,在以前的文章中已经讨论过了,在此便不再赘述。(在这次的方法中,使用vector+pair的形式存储,first为该点的邻接点,second为到达该邻接点的边权)
stack<int> s;
int tpxv[10100];
int rudu[10100];
vector<pair<int,int> > v[10100];//first为邻接点,second为权值
void Tpsort(int n)
{
s.push(0);//虚源
int i=0,j=0;
for(i=0;i<=n+1;i++)
{
if(s.empty()==1)
{
cout<<'0'<<'\n';
exit(0);
}
int x=s.top();
s.pop();
tpxv[j]=x;
++j;
vector<pair<int,int> >::iterator it=v[x].begin();
for(;it!=v[x].end();++it)
{
rudu[it->first]--;
if(rudu[it->first]==0)
s.push(it->first);
}
}
}
使用正序拓扑序列求一遍各点最早开始时间ve,再使用逆序拓扑序列求一遍最晚开始时间vl。ve=vl的点,即是关键活动点。
int ve[10100];
int vl[10100];
void CriticalPath(int n)
{
int i=0;
Tpsort(n);
for(i=0;i<=n;++i)
{
vector<pair<int,int> >::iterator it=v[tpxv[i]].begin();
for(;it!=v[tpxv[i]].end();++it)
{
if(ve[it->first]<ve[tpxv[i]]+it->second)
ve[it->first]=ve[tpxv[i]]+it->second;
}
}
for(i=0;i<=n+1;i++) vl[i]=ve[n+1];//逆序求最迟
for(i=n;i>=0;--i)
{
vector<pair<int,int> >::iterator it=v[tpxv[i]].begin();
for(;it!=v[tpxv[i]].end();++it)
{
if(vl[it->first]<vl[tpxv[i]]+it->second)
vl[tpxv[i]]=vl[it->first]-it->second;
}
}
}
将输出的大数,一位位存储进vector,来个reverse反转一下,就是一位位的大数,具体实现在前几次的题解中的大数加法完全类似,这里只是做了一下封装,故不再赘述。
class GJD//高精度
{
public:
vector<int> v;//存储高精度数
int flag;//标记
GJD(int=0);
GJD operator=(GJD gjd);
GJD operator+(GJD gjd);
GJD &operator+=(GJD gjd);
GJD operator-(GJD gjd);
friend ostream &operator<<(ostream &out,GJD &gjd);
//~GJD()=0;
};
ostream &operator<<(ostream &out,GJD &gjd)
{
for(int i=0;i<gjd.v.size();++i) out<<gjd.v.at(i);
return out;
}
GJD::GJD(int n)
{
int temp=n;
if(temp==0)
{
flag=0;
v.push_back(0);
}
else
{
flag=1;
while(temp!=0)
{
v.push_back(temp%10);
temp=temp/10;
}
reverse(v.begin(),v.end());
}
}
GJD GJD::operator=(GJD gjd)
{
v.assign(gjd.v.begin(),gjd.v.end());
flag=gjd.flag;
return *this;
}
GJD GJD::operator+(GJD gjd)
{
GJD ret;
ret.v.clear();
ret.flag=gjd.flag;
int i=this->v.size()-1;
int j=gjd.v.size()-1;
int fg=0;//标记进位
while(i>=0&&j>=0)
{
int temp=this->v.at(i)+gjd.v.at(j);
if(fg==1){fg=0;temp=temp+1;};
if(temp>=10){fg=1;temp=temp-10;};
ret.v.push_back(temp);
--i;--j;
}
while(i>=0)
{
int temp=this->v.at(i);
if(fg==1){fg=0;temp=temp+1;};
if(temp>=10){fg=1;temp=temp-10;};
ret.v.push_back(temp);
--i;
}
while(j>=0)
{
int temp=gjd.v.at(j);
if(fg==1){fg=0;temp=temp+1;};
if(temp>=10){fg=1;temp=temp-10;};
ret.v.push_back(temp);
--j;
}
if(fg==1)
{
ret.v.push_back(1);
fg=0;
}
reverse(ret.v.begin(),ret.v.end());
return ret;
}
GJD GJD::operator-(GJD gjd)
{
GJD ret;
ret.v.clear();
ret.flag=gjd.flag;
int i=this->v.size()-1;
int j=gjd.v.size()-1;
int fg=0;//标记进位
while(i>=0&&j>=0)
{
int temp=this->v.at(i)-gjd.v.at(j);
if(fg==1){fg=0;temp=temp-1;};
if(temp<0){fg=1;temp=temp+10;};
ret.v.push_back(temp);
--i;--j;
}
while(i>=0)
{
int temp=this->v.at(i);
if(fg==1){fg=0;temp=temp-1;};
if(temp<0){fg=1;temp=temp+10;};
ret.v.push_back(temp);
--i;
}
// while(j>=0)
// {
// int temp=gjd.v.at(j);
// if(fg==1){fg=0;temp=temp+1;};
// if(temp>=10){fg=1;temp=temp-10;};
// ret.v.push_back(temp);
// --j;
// }
// if(fg==1)
// {
// ret.v.push_back(1);
// fg=0;
// }
int f=ret.v.size()-1;
while(!ret.v.at(f))
{
ret.v.pop_back();
--f;
}
reverse(ret.v.begin(),ret.v.end());
return ret;
}
GJD &GJD::operator+=(GJD gjd)
{
*this=*this+gjd;
return *this;
}
有了上述的关键路径已经高精度算法,只需使用dfs遍历各个关键活动点(ve=vl的点),并在DFS(x)的开始,记录jieguo的值。
#include
using namespace std;
class GJD//高精度
{
public:
vector<int> v;//存储高精度数
int flag;//标记
GJD(int=0);
GJD operator=(GJD gjd);
GJD operator+(GJD gjd);
GJD &operator+=(GJD gjd);
GJD operator-(GJD gjd);
friend ostream &operator<<(ostream &out,GJD &gjd);
//~GJD()=0;
};
ostream &operator<<(ostream &out,GJD &gjd)
{
for(int i=0;i<gjd.v.size();++i) out<<gjd.v.at(i);
return out;
}
GJD::GJD(int n)
{
int temp=n;
if(temp==0)
{
flag=0;
v.push_back(0);
}
else
{
flag=1;
while(temp!=0)
{
v.push_back(temp%10);
temp=temp/10;
}
reverse(v.begin(),v.end());
}
}
GJD GJD::operator=(GJD gjd)
{
v.assign(gjd.v.begin(),gjd.v.end());
flag=gjd.flag;
return *this;
}
GJD GJD::operator+(GJD gjd)
{
GJD ret;
ret.v.clear();
ret.flag=gjd.flag;
int i=this->v.size()-1;
int j=gjd.v.size()-1;
int fg=0;//标记进位
while(i>=0&&j>=0)
{
int temp=this->v.at(i)+gjd.v.at(j);
if(fg==1){fg=0;temp=temp+1;};
if(temp>=10){fg=1;temp=temp-10;};
ret.v.push_back(temp);
--i;--j;
}
while(i>=0)
{
int temp=this->v.at(i);
if(fg==1){fg=0;temp=temp+1;};
if(temp>=10){fg=1;temp=temp-10;};
ret.v.push_back(temp);
--i;
}
while(j>=0)
{
int temp=gjd.v.at(j);
if(fg==1){fg=0;temp=temp+1;};
if(temp>=10){fg=1;temp=temp-10;};
ret.v.push_back(temp);
--j;
}
if(fg==1)
{
ret.v.push_back(1);
fg=0;
}
reverse(ret.v.begin(),ret.v.end());
return ret;
}
GJD GJD::operator-(GJD gjd)
{
GJD ret;
ret.v.clear();
ret.flag=gjd.flag;
int i=this->v.size()-1;
int j=gjd.v.size()-1;
int fg=0;//标记进位
while(i>=0&&j>=0)
{
int temp=this->v.at(i)-gjd.v.at(j);
if(fg==1){fg=0;temp=temp-1;};
if(temp<0){fg=1;temp=temp+10;};
ret.v.push_back(temp);
--i;--j;
}
while(i>=0)
{
int temp=this->v.at(i);
if(fg==1){fg=0;temp=temp-1;};
if(temp<0){fg=1;temp=temp+10;};
ret.v.push_back(temp);
--i;
}
// while(j>=0)
// {
// int temp=gjd.v.at(j);
// if(fg==1){fg=0;temp=temp+1;};
// if(temp>=10){fg=1;temp=temp-10;};
// ret.v.push_back(temp);
// --j;
// }
// if(fg==1)
// {
// ret.v.push_back(1);
// fg=0;
// }
int f=ret.v.size()-1;
while(!ret.v.at(f))
{
ret.v.pop_back();
--f;
}
reverse(ret.v.begin(),ret.v.end());
return ret;
}
GJD &GJD::operator+=(GJD gjd)
{
*this=*this+gjd;
return *this;
}
stack<int> s;
int tpxv[10100];
int rudu[10100];
vector<pair<int,int> > v[10100];//first为邻接点,second为权值
void Tpsort(int n)
{
s.push(0);//虚源
int i=0,j=0;
for(i=0;i<=n+1;i++)
{
if(s.empty()==1)
{
cout<<'0'<<'\n';
exit(0);
}
int x=s.top();
s.pop();
tpxv[j]=x;
++j;
vector<pair<int,int> >::iterator it=v[x].begin();
for(;it!=v[x].end();++it)
{
rudu[it->first]--;
if(rudu[it->first]==0)
s.push(it->first);
}
}
}
int ve[10100];
int vl[10100];
void CriticalPath(int n)
{
int i=0;
Tpsort(n);
for(i=0;i<=n;++i)
{
vector<pair<int,int> >::iterator it=v[tpxv[i]].begin();
for(;it!=v[tpxv[i]].end();++it)
{
if(ve[it->first]<ve[tpxv[i]]+it->second)
ve[it->first]=ve[tpxv[i]]+it->second;
}
}
for(i=0;i<=n+1;i++) vl[i]=ve[n+1];//逆序求最迟
for(i=n;i>=0;--i)
{
vector<pair<int,int> >::iterator it=v[tpxv[i]].begin();
for(;it!=v[tpxv[i]].end();++it)
{
if(vl[it->first]<vl[tpxv[i]]+it->second)
vl[tpxv[i]]=vl[it->first]-it->second;
}
}
}
GJD jieguo;
GJD vis[10100];
void DFS(int x,int n)
{
if(x==n+1)
{
jieguo=jieguo+1;
return ;
}
GJD tmp=jieguo;
vector<pair<int,int> >::iterator it=v[x].begin();
for(;it!=v[x].end();++it)//遍历其所有邻边
{
if(vis[it->first].flag==1)//如果已经求出其后面的关键路径数
{
jieguo=jieguo+vis[it->first]-1;
continue;
}
if(ve[it->first]==vl[it->first])//只有ve=vl才是关键路径上的点
DFS(it->first,n);
}
vis[x]=jieguo-tmp+1;
}
int weight[10100];
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
int N,M;
cin>>N>>M;
for(int i=1;i<=N;i++) cin>>weight[i];
int u,V;
for(int i=1;i<=M;i++)//初始化
{
cin>>u>>V;
v[u].push_back(make_pair(V,weight[u]));
rudu[V]++;
}
for(int i=1;i<=N;i++)
{
if(rudu[i]==0)
{
v[0].push_back(make_pair(i,0));
rudu[i]++;
}
}
for(int i=1;i<=N;i++)
{
if(v[i].size()==0)
{
v[i].push_back(make_pair(N+1,weight[i]));
rudu[N+1]++;
}
}
CriticalPath(N);
DFS(0,N);
cout<<vl[N+1]<<'\n';
cout<<jieguo<<'\n';
}