JLU数据结构第七次上机实验解题报告

T1

题目

有一个N个数的序列A:1,2,……,N。有一个后进先出容器D,容器的容量为C。如果给出一个由1到N组成的序列,那么可否由A使用容器D的插入和删除操作得到。

INPUT

第1行,2个整数T和C,空格分隔,分别表示询问的组数和容器的容量,1≤C≤N。

第2到T+1行,每行的第1个整数N,表示序列的元素数。接下来N个整数,表示询问的序列。

OUTPUT

T行。若第i组的序列能得到,第i行输出Yes;否则,第i行输出No,1≤i≤T。

Sample

INPUT

2 2
5 1 2 5 4 3
4 1 3 2 4

OUTPUT

No
Yes

Time Limit

100ms

Memory Limit

10MB

Data range

1≤N≤10000  1≤T≤10

Solution

模拟出入栈即可,若当前栈顶是目标数列下一个元素不断出栈,否则将原序列下一个元素入栈

code

#include <bits/stdc++.h>

using namespace std;

int T,C;
int a[10005];
int b[10005];
int stac[10005],top;

int main(){
	scanf("%d%d",&T,&C);
	while(T--){
		int n;scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			b[i] = i;
		}
		int now1 = 0,now = 0,top = 0,flag = 0;
		while(now < n){
			while(a[now + 1] != stac[top] && top <= C && now1 < n)stac[++top] = b[++now1];
			if(top > C || (now1 == n && stac[top] != a[now + 1])){
				printf("No\n");
				flag = 1;
				break;
			}
			stac[top--];
			now++;
		}
		if(flag)continue;
		printf("Yes\n");
	}
	return 0;
}
/*
1 2 5 4 3
1 2 3 4 5
1 3 2 4
1 2 3 4
*/

T2

题目

对n 个正整数,进行如下操作:每一次删去其中两个数 a 和 b,然后加入一个新数:a*b+1,如此下去直到 只剩下一个数。所有按这种操作方式最后得到的数中,最大的为max,最小的为min,计算max-min。

INPUT

第1行:n,数列元素的个数。

第2行:n 个用空格隔开的数x。

OUTPUT

1行,所求max-min。

Sample

INPUT

3
2 4 3

OUTPUT

2

Time Limit

100ms

Memory Limit

64MB

Data range

1<=n<=16  x<=10

Solution

贪心,不断取最大相乘和不断取最小相乘

code

#include <bits/stdc++.h>

using namespace std;

int n;
int a[100005],mx;
bool used[100005];
int maxx,minn;
priority_queue<int> q1,q2;

int main(){
	scanf("%d",&n);
	mx = n;
	minn = 1e9;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		q1.push(a[i]);
		q2.push(-a[i]);
	}
	while(q1.size() > 1){
		int x = q1.top();q1.pop();
		int y = q1.top();q1.pop();
		q1.push(x * y + 1);
	}
	maxx = max(maxx,q1.top());
	minn = min(minn,q1.top());
	while(q2.size() > 1){
		int x = -q2.top();q2.pop();
		int y = -q2.top();q2.pop();
		q2.push(-(x * y + 1));
	}
	maxx = max(maxx,-q2.top());
	minn = min(minn,-q2.top());
	printf("%d",maxx - minn);
	return 0;
}

T3

题目

给定一棵二叉树T,每个结点赋一个权值。计算从根结点到所有结点的最短路径长度。路径长度定义为:路径上的每个顶点的权值和。

INPUT

第1行,1个整数n,表示二叉树T的结点数,结点编号1..n。

第2行,n个整数,空格分隔,表示T的先根序列,序列中结点用编号表示。

第3行,n个整数,空格分隔,表示T的中根序列,序列中结点用编号表示。

第4行,n个整数Wi,空格分隔,表示T中结点的权值,1≤i≤n。

OUTPUT

1行,n个整数,表示根结点到其它所有结点的最短路径长度。

Sample

INPUT

4
1 2 4 3
4 2 1 3
1 -1 2 3

OUTPUT

1 0 3 3

Time Limit

1000ms

Memory Limit

10MB

Data range

1≤n≤20000  -10000≤Wi≤10000

Solution

难点在于前中根序列得到树,需要用类似线段树的方法递归下去建树

code

#include <bits/stdc++.h>

using namespace std;

int n;
int fir[100005];
int mid[100005];
int val[100005];
long long dis[100005];
bool inq[100005];

struct Node{
	int lef,rig;
}v[100005];

int dfs(int fir1,int fir2,int mid1,int mid2){
	int rootIdx;
	for(int i=mid1;i<=mid2;i++) {
		if(mid[i] == fir[fir1]) {
			rootIdx = i;
			break;
		}
	}
	if(rootIdx != mid1) {
		v[fir[fir1]].lef = dfs(fir1 + 1,fir1 + (rootIdx - mid1),mid1,rootIdx - 1);
	}
	if(rootIdx != mid2) {
		v[fir[fir1]].rig = dfs(fir1 + (rootIdx - mid1) + 1,fir2,rootIdx + 1,mid2);
	}
	return fir[fir1];
}

void spfa(){
	queue<int> q;
	q.push(fir[1]);
	inq[fir[1]] = 1;
	while(!q.empty()){
		int u = q.front();q.pop();
		inq[u] = 0;
		if(v[u].lef){
			int to = v[u].lef;
			if(dis[to] > dis[u] + val[to]){
				dis[to] = dis[u] + val[to];
				if(!inq[to]){
					q.push(to);
					inq[to] = 1;
				}
			}
		}
		if(v[u].rig){
			int to = v[u].rig;
			if(dis[to] > dis[u] + val[to]){
				dis[to] = dis[u] + val[to];
				if(!inq[to]){
					q.push(to);
					inq[to] = 1;
				}
			}
		}
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)dis[i] = 300000000;
	for(int i=1;i<=n;i++){
		scanf("%d",&fir[i]);
		v[i].lef = v[i].rig = 0;
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&mid[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&val[i]);
	dis[fir[1]] = val[fir[1]];
	dfs(1,n,1,n);
	spfa();
	for(int i=1;i<=n;i++){
		printf("%lld",dis[i]);
		if(i != n)printf(" ");
	}
	return 0;
}
/*
6
1 2 4 5 3 6
4 2 5 1 3 6
1 2 3 4 5 6
*/

T4

题目

组装一个产品需要 n 个零件。生产每个零件都需花费一定的时间。零件的生产可以并行进行。有些零件的生产有先后关系,只有一个零件的之前的所有零件都生产完毕,才能开始生产这个零件。如何合理安排工序,才能在最少的时间内完成所有零件的生产。在保证最少时间情况下,关键方案有多少种,关键方案是指从生产开始时间到结束时间的一个零件生产序列,序列中相邻两个零件的关系属于事先给出的零件间先后关系的集合,序列中的每一个零件的生产都不能延期。

INPUT

第1行,2个整数n和m,用空格分隔,分别表示零件数和关系数,零件编号1..n 。

第2行,n个整数Ti,用空格分隔,表示零件i的生产时间,1≤i≤n 。

第3到m+2行,每行两个整数i和j,用空格分隔,表示零件i要在零件j之前生产。

OUTPUT

第1行,1个整数,完成生产的最少时间。

第2行,1个整数,关键方案数,最多100位。

如果生产不能完成,只输出1行,包含1个整数0.

Sample

INPUT

4 4
1 2 2 1
1 2
1 3
2 4
3 4

OUTPUT

4
2

Time Limit

200ms

Memory Limit

64MB

Data range

1≤n≤10000  0≤m≤100000  1≤Ti≤100

Solution

关键路径,利用拓扑排序递推得出每个事件发生的最早,再通过加法原理与关键活动得出路径数,由于答案过大需要高精

code

#include <bits/stdc++.h>

using namespace std;

const int N = 105;

struct Add{
	int a[N];
	Add(){memset(a,0,sizeof a);}
	void read(){
		memset(a,0,sizeof a);
		char s[N];
		scanf("%s",s+1);
		a[0] = strlen(s+1);
		for(int i=a[0];i>=1;i--)
			a[a[0]-i+1] = s[i] - '0';
	}
	void get(int x){
		memset(a,0,sizeof a);
		while(x){
			a[++a[0]] = x % 10;
			x /= 10;
		}
	}
	void print(){
		for(int i=a[0];i>=1;i--)
			printf("%d",a[i]);
	}
	Add operator +(const Add &b){
		Add res;res.a[0] = max(a[0],b.a[0]);
		for(int i=1;i<=res.a[0];i++)
			res.a[i] += a[i] + b.a[i],res.a[i+1] += res.a[i]/10,res.a[i] %= 10;
		if(res.a[res.a[0]+1])res.a[0] ++;
		return res;
	}
};

int n,m;
int to[120005],nex[120005],head[120005],ce;
int val[120005];
int ve[120005],vl[120005];
int ee[120005],el[120005];
int topoarr[120005],now;
int in[120005];
int in1[120005];
int T[120005];
Add ans[120005];

void add(int u,int v,int w){
	to[++ce] = v,nex[ce] = head[u],head[u] = ce,val[ce] = w;
}

void topo(){
	queue<int> q;
	q.push(0);
	topoarr[++now] = 0;
	while(!q.empty()){
		int u = q.front();q.pop();
		topoarr[++now] = u;
		for(int i=head[u];i;i=nex[i]){
			int v = to[i];
			in[v]--;
			if(ve[u] + val[i] > ve[v])
				ve[v] = ve[u] + val[i];
			if(!in[v])q.push(v);
		}
	}
	for(int i=1;i<=n;i++)
		if(in[i]){printf("0");exit(0);}
	for(int i=0;i<=n+1;i++)vl[i] = ve[n + 1];
	for(int u=n;u>=0;u--)
		for(int i=head[u];i;i=nex[i]){
			int v = to[i];
			if(vl[v] - val[i] < vl[u])
				vl[u] = vl[v] - val[i];
		}
}

void bfs(){
	queue<int> q;
	q.push(0);
	ans[0].get(1);
	while(!q.empty()){
		int u = q.front();q.pop();
		for(int i=head[u];i;i=nex[i]){
			int v = to[i];
			in1[v]--;
			ee[i] = ve[u],el[i] = vl[v] - val[i];
			if(ee[i] == el[i])
				ans[v] = ans[v] + ans[u];
			if(!in1[v])q.push(v);
		}
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&T[i]);
		add(0,i,T[i]);
		in[i]++;
		in1[i]++;
		add(i,n + 1,0);
		in[n + 1]++;
		in1[n + 1]++;
	}
	for(int i=1;i<=m;i++){
		int u,v;scanf("%d%d",&u,&v);
		add(u,v,T[v]);
		in[v]++;
		in1[v]++;
	}
	topo();
	bfs();
	printf("%d\n",ve[n + 1]);
	ans[n + 1].print();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值