数据结构_优先队列
2014-11-29 19:13
323 查看
数据结构与算法实验题 11.4 4 舞蹈课
★ 实验任务
有 n 个人参加舞蹈课,每个人以他的舞蹈技能 ai 为特点。舞蹈课开始
前,他们从左到右排成一行。当队伍中至少含有一名男生和一名女生时,下
面的过程会重复进行:
站在相邻位置的男女生且舞蹈技能差异最小的开始跳舞。 如果有很多对,
最靠左边的开始跳舞。跳舞完以后就离开。
舞蹈技能的差异为|ai-aj|。你的任务是找到每一对,并找出是按什么顺
序开始跳舞。
★ 数据输入
输入的第 1 行是一个正整数 n(1 <= n <= 2 * 10^5),表示人的个数。
第 2 行包含 n 个字符”B”或”G”,分别代表男生和女生,之间没有用空格
隔开。第 3 行包含 n 个整数 ai (1 ≤ ai ≤ 10^7),表示每个人的舞蹈技能。按
从左到右的顺序排列。
★ 数据输 出
输出 k 对。接下去输出 k 行,每行包含 2 个整数,表示组成一对的男女
生的序号。 按从左到右从 1 到 n 开始排序。 当一对舞者离开时不用重新排序。
打印每一对时按递增打印。按跳舞的顺序打印。
输入示例 输出示例
4
BGBG
4 2 4 3
2
3 4
1 2
14
BGBGBBGGGBBBBG
4 4 4 4 5 6 7 8 9 10 11 12 5 5
6
1 2
3 4
13 14
6 7
9 10
5 8
14
BGBGBBGGGBBBBG
4 4 4 4 5 6 7 8 9 9 8 7 6 5
6
1 2
3 4
9 10
8 11
7 12
13 14
5
BGGBB
25 4 3 2 1
2
3 4
2 5
8
BGBGBGBG
100 1 10 10 4 6 100 96
4
3 4
5 6
7 8
1 2
以下差值均默认为绝对值下的
1.每次选出男女相邻的差值(绝对值)最小的,并输出TA们下标
问题1).每个人与他的前面那个人和后面那个人各有一个差值,该怎么表示?
ans:作出如下规定:用数组sub来记录sub[i]表示i与i+1的差值
问题2).选取的必须是异性间的最小的差值,该怎么处理?
ans:可以把同性的差值+同一个足够大的数,
因为每个差值最大不会大于10^7,因此这个数可以是2*10^7。
问题3).每走掉一对男女,都会对其他人的差值造成影响,该怎么处理这种影响?
可能的影响有:1.sub改变了2.下标i-1,i+1可能已经走掉了
1.sub改变了:
比如
5
BGGBB
25 4 3 2 1
原来sub[2]=4-3+2*10^7,走掉3,4后,会变成sub[2]=4-1;
key--->发现只对前面的sub有影响!
2.下标i-1,i+1可能已经走掉了:
key->>>>第二对走的是2,5 怎么知道2的后面那个数是5?
用next_step[i]表示i的后一个未走的人的下标
每次走掉一对记得更新该数组
方法1:(较慢,测试得大概是方法2的1.5倍时间,且内存消耗也较大)
自己写优先队列(速度较快)
方法2:
1.最初把所有满足与后面相邻点为异性的点push到优先队列中
2.每次取出q.top();并且取出点需要满足2个条件才可以输出 print->index,next_step[print->index];
1)条件一:该点未被访问过;
2)条件二:该结点的sub必须等于最后更新的sub值;这个十分重要,因为每个点的sub值可能被更新数次!其中可能数次满足被push的条件。
3.在每次取出q.top()后,q.pop();并且更新pre_step,next_step数组,同时更新ready_dance[pre_step[print->index]](即出去点的前相邻点的sub值),如果出去点的前相邻点满足与更新后的后相邻点位异性,那么push它
ps:
条件二的具体分析:
8
BGBGBGBG
100 1 10 10 4 6 100 96
1.这八个点都满足push条件,因此全部push
循环1:
2.队列top()为结点3
检查是否满足2个条件,发现是的
输出3 4
3.更新
pre_step[next_step[next_step[3]]]=pre_step[3];
next_step[pre_step[3]]=next_step[next_step[3]]];
更新 ready_dance[2].sub=4-1=3并且被push
同时发现更新后:
read_dance[2].sub=4-1=3;且第2点与后相邻的第4点为异性,所以push
循环2:
队列top()为结点5
......结点2被第二次更新
循环3:
队列top()为结点2,当初结点2第一次后sub=3,虽然后来又被更新为99但第一次更新的已经被Push
此时发现 print->sub!=ready_dance[print->index].sub(也就是不满足条件2,因此不输出)
...
方法2:(较快)
自己写队列
★ 实验任务
有 n 个人参加舞蹈课,每个人以他的舞蹈技能 ai 为特点。舞蹈课开始
前,他们从左到右排成一行。当队伍中至少含有一名男生和一名女生时,下
面的过程会重复进行:
站在相邻位置的男女生且舞蹈技能差异最小的开始跳舞。 如果有很多对,
最靠左边的开始跳舞。跳舞完以后就离开。
舞蹈技能的差异为|ai-aj|。你的任务是找到每一对,并找出是按什么顺
序开始跳舞。
★ 数据输入
输入的第 1 行是一个正整数 n(1 <= n <= 2 * 10^5),表示人的个数。
第 2 行包含 n 个字符”B”或”G”,分别代表男生和女生,之间没有用空格
隔开。第 3 行包含 n 个整数 ai (1 ≤ ai ≤ 10^7),表示每个人的舞蹈技能。按
从左到右的顺序排列。
★ 数据输 出
输出 k 对。接下去输出 k 行,每行包含 2 个整数,表示组成一对的男女
生的序号。 按从左到右从 1 到 n 开始排序。 当一对舞者离开时不用重新排序。
打印每一对时按递增打印。按跳舞的顺序打印。
输入示例 输出示例
4
BGBG
4 2 4 3
2
3 4
1 2
14
BGBGBBGGGBBBBG
4 4 4 4 5 6 7 8 9 10 11 12 5 5
6
1 2
3 4
13 14
6 7
9 10
5 8
14
BGBGBBGGGBBBBG
4 4 4 4 5 6 7 8 9 9 8 7 6 5
6
1 2
3 4
9 10
8 11
7 12
13 14
5
BGGBB
25 4 3 2 1
2
3 4
2 5
8
BGBGBGBG
100 1 10 10 4 6 100 96
4
3 4
5 6
7 8
1 2
以下差值均默认为绝对值下的
1.每次选出男女相邻的差值(绝对值)最小的,并输出TA们下标
问题1).每个人与他的前面那个人和后面那个人各有一个差值,该怎么表示?
ans:作出如下规定:用数组sub来记录sub[i]表示i与i+1的差值
问题2).选取的必须是异性间的最小的差值,该怎么处理?
ans:可以把同性的差值+同一个足够大的数,
因为每个差值最大不会大于10^7,因此这个数可以是2*10^7。
问题3).每走掉一对男女,都会对其他人的差值造成影响,该怎么处理这种影响?
可能的影响有:1.sub改变了2.下标i-1,i+1可能已经走掉了
1.sub改变了:
比如
5
BGGBB
25 4 3 2 1
原来sub[2]=4-3+2*10^7,走掉3,4后,会变成sub[2]=4-1;
key--->发现只对前面的sub有影响!
2.下标i-1,i+1可能已经走掉了:
key->>>>第二对走的是2,5 怎么知道2的后面那个数是5?
用next_step[i]表示i的后一个未走的人的下标
每次走掉一对记得更新该数组
方法1:(较慢,测试得大概是方法2的1.5倍时间,且内存消耗也较大)
#include<cstdio> #include<cstring> #define F 20000000 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int N=200100; bool data ,can_dance ; char str ; int pre_step ,sub ,next_step ; struct node { int index,sub; }; node ready_dance ; node sum[N*3]; node min(const node &a,const node &b){ if(a.sub!=b.sub) return a.sub<b.sub?a:b; else return a.index<b.index?a:b; } int cnt=1; //!线段树单点更新 void push_up(int rt){ sum[rt]=min(sum[rt<<1],sum[rt<<1|1]); } void build(int l,int r,int rt) { if(l==r) { sum[rt]=ready_dance[cnt++]; return; } int m=(l+r)>>1; build(lson);build(rson); push_up(rt); } void update2(int cur_i,int next_i,int n) { int pre,cur; if(cur_i==0) return;//第一个点的前面没有点 pre=sub[cur_i],cur=sub[next_i]; ready_dance[cur_i].sub=cur-pre<0?pre-cur:cur-pre; if(!(data[cur_i]^data[next_i])||next_i>n)ready_dance[cur_i].sub+=F; } void update(int x,int c,int l,int r,int rt) { if(l==r) { sum[rt].sub=c; ready_dance[x].sub=F+F;//相当于删除改点 return ; } int m=(l+r)>>1; if(x<=m) update(x,c,lson); else update(x,c,rson); push_up(rt); } //!线段树单点更新 void Init() { int i; pre_step[0]=-1; for(i=1;i<N;++i){ pre_step[i]=i-1; next_step[i-1]=i; } } int main() { Init(); int n,i,pre,cur,girls,boys; scanf("%d",&n); scanf("%s",str); //!data数组记录男女相对位置 for(i=0,girls=boys=0;i<n;++i) if(str[i]=='B'){ ++boys; data[i+1]=true; } else ++girls; //!data数组记录男女相对位置 //!sub数组记录第k数与第k+1数的差绝对值,read_dance数组记录差值与原下标 for(i=1;i<=n;++i){ scanf("%d",&sub[i]); cur=sub[i]; if(i>1){ ready_dance[i-1].sub=cur-pre<0?pre-cur:cur-pre; if(!(data[i-1]^data[i]))ready_dance[i-1].sub+=F; ready_dance[i-1].index=i-1; } pre=cur; } ready_dance .sub=F+F;//F+F这个值足够大,可以保证在选择时不被选中(相当于排除该点) //!sub数组记录第k数与第k+1数的差绝对值,read_dance数组记录差值与原下标 //!这里pre_step[i]与next_step[i],分别表示i原下标的前一个原下标和后一个原下标 //!不能根据i+1,i-1来表示下标i的后面与前面,i+1,i-1可能在之前已经走掉~ build(1,n,1); node tmp; node *print=&tmp; printf("%d\n",girls<boys?girls:boys); while((girls>0&&boys>0)){ tmp=sum[1]; pre_step[next_step[next_step[print->index]]]=pre_step[print->index]; next_step[pre_step[print->index]]=next_step[next_step[print->index]]; update2(pre_step[print->index],next_step[pre_step[print->index]],n); update(pre_step[print->index],ready_dance[pre_step[print->index]].sub,1,n,1);//更新前面点 update(print->index,3*F,1,n,1);update(next_step[print->index],3*F,1,n,1);//删除现在头结点 printf("%d %d\n",print->index,next_step[print->index]); --girls,--boys; } }
自己写优先队列(速度较快)
#include<stdio.h> #include<malloc.h> #define parent cur>>1 #define cur_lson cur<<1 #define cur_rson cur<<1|1 const int N=200100; struct node { int index,sub; }; typedef node SetItem; typedef struct minheap *Heap; typedef struct minheap { int last; SetItem *heap; }Minheap; bool data ,vis ; char str ; int pre_step ,sub ,next_step ; node ready_dance ; Minheap q; Heap H; bool less(const SetItem&a,const SetItem &b) { if(a.sub!=b.sub) return a.sub<b.sub; else return a.index<b.index; } void Init() { int i; pre_step[0]=-1; for(i=1;i<N;++i){ pre_step[i]=i-1; next_step[i-1]=i; } } void MinHeapInit() { H=(Heap)malloc(sizeof(*H)); H->heap=(SetItem*)malloc((N+1)*sizeof(SetItem)); H->last=0; } void max_heapify(int cur,int cur_son,SetItem last) { while(cur_son<=H->last){ if(cur_son<H->last&&less(H->heap[cur_rson],H->heap[cur_lson]))cur_son=cur_rson; if(!less(H->heap[cur_son],last))break; H->heap[cur]=H->heap[cur_son]; cur=cur_son; cur_son=cur_lson; } H->heap[cur]=last; } void push(SetItem x) { int cur; // if(H->last==H->maxsize) return ; cur=++H->last; while(cur!=1&&less(x,H->heap[parent])){ H->heap[cur]=H->heap[parent]; cur=parent; } H->heap[cur]=x; } SetItem top_pop() { int cur,cur_son; SetItem top,last; top=H->heap[1]; last=H->heap[H->last--]; cur=1,cur_son=cur_lson; max_heapify(cur,cur_son,last); return top; } int main() { Init();MinHeapInit(); int n,i,pre,cur,girls,boys; scanf("%d",&n); scanf("%s",str); for(i=0,girls=boys=0;i<n;++i) if(str[i]=='B'){ ++boys; data[i+1]=true; } else ++girls; for(i=1;i<=n;++i){ scanf("%d",&sub[i]); cur=sub[i]; if(i>1){ ready_dance[i-1].sub=cur-pre<0?pre-cur:cur-pre; ready_dance[i-1].index=i-1; if((data[i-1]^data[i]))push(ready_dance[i-1]); } pre=cur; } node tmp;node *print=&tmp; printf("%d\n",girls<boys?girls:boys); int nextstep,prestep; while((girls>0&&boys>0)){ tmp=top_pop(); if(vis[print->index]||!(data[print->index]^data[next_step[print->index]]))continue; if(print->sub!=ready_dance[print->index].sub)continue; pre_step[next_step[next_step[print->index]]]=pre_step[print->index]; next_step[pre_step[print->index]]=next_step[next_step[print->index]]; nextstep=next_step[pre_step[print->index]], prestep=pre_step[print->index]; ready_dance[prestep].sub=sub[prestep]-sub[nextstep]<0?(sub[nextstep]-sub[prestep]):(sub[prestep]-sub[nextstep]); if(prestep>0&&nextstep<=n&&(data[prestep]^data[nextstep])) { push(ready_dance[prestep]); } printf("%d %d\n",print->index,next_step[print->index]); --girls,--boys; vis[print->index]=vis[next_step[print->index]]=true; } }
方法2:
1.最初把所有满足与后面相邻点为异性的点push到优先队列中
2.每次取出q.top();并且取出点需要满足2个条件才可以输出 print->index,next_step[print->index];
1)条件一:该点未被访问过;
2)条件二:该结点的sub必须等于最后更新的sub值;这个十分重要,因为每个点的sub值可能被更新数次!其中可能数次满足被push的条件。
3.在每次取出q.top()后,q.pop();并且更新pre_step,next_step数组,同时更新ready_dance[pre_step[print->index]](即出去点的前相邻点的sub值),如果出去点的前相邻点满足与更新后的后相邻点位异性,那么push它
ps:
条件二的具体分析:
8
BGBGBGBG
100 1 10 10 4 6 100 96
1.这八个点都满足push条件,因此全部push
循环1:
2.队列top()为结点3
检查是否满足2个条件,发现是的
输出3 4
3.更新
pre_step[next_step[next_step[3]]]=pre_step[3];
next_step[pre_step[3]]=next_step[next_step[3]]];
更新 ready_dance[2].sub=4-1=3并且被push
同时发现更新后:
read_dance[2].sub=4-1=3;且第2点与后相邻的第4点为异性,所以push
循环2:
队列top()为结点5
......结点2被第二次更新
循环3:
队列top()为结点2,当初结点2第一次后sub=3,虽然后来又被更新为99但第一次更新的已经被Push
此时发现 print->sub!=ready_dance[print->index].sub(也就是不满足条件2,因此不输出)
...
方法2:(较快)
/* 8 BGBGBGBG 100 1 10 10 4 6 100 96 */ #include<cstdio> #include<cstring> #include<queue> #define F 20000000 using namespace std; const int N=200100; bool data ; char str ; int pre_step ,sub ,next_step ; bool vis ; struct node { int index,sub; bool operator <(const node &b)const{ if(sub!=b.sub) return sub>b.sub; else return index>b.index; } }; node ready_dance ; priority_queue<node> q; int cnt=1; void Init() { int i; pre_step[0]=-1; for(i=1;i<N;++i){ pre_step[i]=i-1; next_step[i-1]=i; } } int main() { Init(); int n,i,pre,cur,girls,boys; scanf("%d",&n); scanf("%s",str); //!data数组记录男女相对位置 for(i=0,girls=boys=0;i<n;++i) if(str[i]=='B'){ ++boys; data[i+1]=true; } else ++girls; //!data数组记录男女相对位置 //!sub数组记录第k数与第k+1数的差绝对值,read_dance数组记录差值与原下标 for(i=1;i<=n;++i){ scanf("%d",&sub[i]); cur=sub[i]; if(i>1){ ready_dance[i-1].sub=cur-pre<0?pre-cur:cur-pre; ready_dance[i-1].index=i-1; if((data[i-1]^data[i]))q.push(ready_dance[i-1]); } pre=cur; } //!sub数组记录第k数与第k+1数的差绝对值,read_dance数组记录差值与原下标 //!这里pre_step[i]与next_step[i],分别表示i原下标的前一个原下标和后一个原下标 //!不能根据i+1,i-1来表示下标i的后面与前面,i+1,i-1可能在之前已经走掉~ node tmp;node *print=&tmp; printf("%d\n",girls<boys?girls:boys); int nextstep,prestep; while((girls>0&&boys>0)){ tmp=q.top();q.pop(); // printf("cur_index=%d cur_next_index=%d\n",print->index,next_step[print->index]); if(vis[print->index]||!(data[print->index]^data[next_step[print->index]]))continue; if(print->sub!=ready_dance[print->index].sub)continue;//有些点会被更新数次,而且每次都会被push进去,必须确保pop出来的与最后一次更新的信息一致 pre_step[next_step[next_step[print->index]]]=pre_step[print->index]; next_step[pre_step[print->index]]=next_step[next_step[print->index]]; nextstep=next_step[pre_step[print->index]], prestep=pre_step[print->index]; ready_dance[prestep].sub=sub[prestep]-sub[nextstep]<0?(sub[nextstep]-sub[prestep]):(sub[prestep]-sub[nextstep]); if(prestep>0&&nextstep<=n&&(data[prestep]^data[nextstep])) { // printf("prestep==%d nextstepp=%d\n",prestep,nextstep); q.push(ready_dance[prestep]); } printf("%d %d\n",print->index,next_step[print->index]); --girls,--boys; vis[print->index]=vis[next_step[print->index]]=true; // show(n); } }
自己写队列
#include<stdio.h> #include<malloc.h> #define parent cur>>1 #define cur_lson cur<<1 #define cur_rson cur<<1|1 const int N=200100; struct node { int index,sub; }; typedef node SetItem; typedef struct minheap { int last; SetItem *heap; }Minheap; typedef struct minheap *Heap; bool data ,vis ; char str ; int pre_step ,sub ,next_step ; node ready_dance ; Heap H; bool less(const SetItem&a,const SetItem &b) { if(a.sub!=b.sub) return a.sub<b.sub; else return a.index<b.index; } void Init() { int i; pre_step[0]=-1; for(i=1;i<N;++i){ pre_step[i]=i-1; next_step[i-1]=i; } } void MinHeapInit() { H=(Heap)malloc(sizeof(*H)); H->heap=(SetItem*)malloc((N+1)*sizeof(SetItem)); H->last=0; } void max_heapify(int cur,int cur_son,SetItem last) { while(cur_son<=H->last){ if(cur_son<H->last&&less(H->heap[cur_rson],H->heap[cur_lson]))cur_son=cur_rson; if(!less(H->heap[cur_son],last))break; H->heap[cur]=H->heap[cur_son]; cur=cur_son; cur_son=cur_lson; } H->heap[cur]=last; } void push(SetItem x) { int cur; // if(H->last==H->maxsize) return ; cur=++H->last; while(cur!=1&&less(x,H->heap[parent])){ H->heap[cur]=H->heap[parent]; cur=parent; } H->heap[cur]=x; } SetItem top_pop() { int cur,cur_son; SetItem top,last; top=H->heap[1]; last=H->heap[H->last--]; cur=1,cur_son=cur_lson; max_heapify(cur,cur_son,last); return top; } int main() { Init();MinHeapInit(); int n,i,pre,cur,girls,boys; scanf("%d",&n); scanf("%s",str); //!data数组记录男女相对位置 for(i=0,girls=boys=0;i<n;++i) if(str[i]=='B'){ ++boys; data[i+1]=true; } else ++girls; //!data数组记录男女相对位置 //!sub数组记录第k数与第k+1数的差绝对值,read_dance数组记录差值与原下标 for(i=1;i<=n;++i){ scanf("%d",&sub[i]); cur=sub[i]; if(i>1){ ready_dance[i-1].sub=cur-pre<0?pre-cur:cur-pre; ready_dance[i-1].index=i-1; if((data[i-1]^data[i]))push(ready_dance[i-1]); } pre=cur; } //!sub数组记录第k数与第k+1数的差绝对值,read_dance数组记录差值与原下标 //!这里pre_step[i]与next_step[i],分别表示i原下标的前一个原下标和后一个原下标 //!不能根据i+1,i-1来表示下标i的后面与前面,i+1,i-1可能在之前已经走掉~ node tmp;node *print=&tmp; printf("%d\n",girls<boys?girls:boys); int nextstep,prestep; while((girls>0&&boys>0)){ tmp=top_pop(); // printf("cur_index=%d cur_next_index=%d\n",print->index,next_step[print->index]); if(vis[print->index]||!(data[print->index]^data[next_step[print->index]]))continue; if(print->sub!=ready_dance[print->index].sub)continue;//有些点会被更新数次,而且每次都会被push进去,必须确保pop出来的与最后一次更新的信息一致 pre_step[next_step[next_step[print->index]]]=pre_step[print->index]; next_step[pre_step[print->index]]=next_step[next_step[print->index]]; nextstep=next_step[pre_step[print->index]], prestep=pre_step[print->index]; ready_dance[prestep].sub=sub[prestep]-sub[nextstep]<0?(sub[nextstep]-sub[prestep]):(sub[prestep]-sub[nextstep]); if(prestep>0&&nextstep<=n&&(data[prestep]^data[nextstep])) { // printf("prestep==%d nextstepp=%d\n",prestep,nextstep); push(ready_dance[prestep]); } printf("%d %d\n",print->index,next_step[print->index]); --girls,--boys; vis[print->index]=vis[next_step[print->index]]=true; // show(n); } }
相关文章推荐
- 数据结构 优先队列 C语言实现
- JAVA数据结构--队列及优先队伍
- 数据结构实现之最小索引优先队列
- 数据结构-优先队列
- 常用数据结构STL实现(优先队列、队列、栈)
- 数据结构: 优先队列的应用
- 数据结构实现之最大索引优先队列
- 堆数据结构+堆排序+最大优先队列的堆的实现
- 【数据结构】回顾优先队列(堆)
- 数据结构 基于队列的广度优先遍历算法判断完全二叉树
- 数据结构-堆实现优先队列(java)
- 【数据结构】之用堆实现优先队列
- 数据结构Java实现07----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列
- 数据结构实现之索引优先队列用例(多路归并)
- 数据结构:优先队列--堆
- 【数据结构】优先队列,堆
- 数据结构:优先队列
- 数据结构入门--优先队列简单排序
- 【数据结构】优先队列和堆
- 【数据结构】浅谈算法和数据结构:优先队列和堆排序