首页 > 技术文章 > 冒泡排序图

harden 2016-11-12 17:09 原文

【问题描述】
有一段使用冒泡排序产生一张图的伪代码如下:
function bubbleSortGraph(n, a[]):
graph = emptyGraph()
repeat
swapped = false
for i = 1 to n - 1:
if a[i] > a[i + 1]:
graph.addEdge(a[i], a[i + 1])
swap(a[i], a[i + 1])
swapped = true
until not swapped
return graph
函数的输入为长度为?的排列?[],输出为一张?个节点的无向图。函数中,
emptyGraph()创造了一张空的无向图,addEdge(x, y)向图中添加了一条 x
和 y 之间的无向边,最后返回的 graph 即产生的无向图。
图的点独立集为图中节点集合的一个子集。如果集合?是图?的点独立集,
那么?中任意两个节点在图?中都没有边直接相连。
给定1~?的一个排列, 请求出按照伪代码生成的无向图的最大点独立集的大
小,以及一定会存在于最大点独立集中的节点。
【输入格式】
输入第一行包含一个整数?。接下来一行包含?个空格分隔的整数,代表序
列?[]。
【输出格式】
输出两行。 第一行包含一个整数, 代表生成的无向图的最大点独立集的大小。
第二行输出最大点独立集中一定会包含的节点在输入序列中对应的下标, 按照从
小到大的顺序输出,以空格分隔。
【样例输入】
3
3 1 2
【样例输出】
2
2 3
【数据规模和约定】
60%的数据,? ≤ 1000。
对于100%的数据,1 ≤ ? ≤ 100,000。
【提示】
一定存在于最大点独立集中的节点数未必等于最大点独立集的大小

/*
  分析可以得出,这是求最长上升子序列。
  分析:冒泡排序时,当i<j&&a[i]<a[j]时,两者一定不会交换,就不会建边,反之则建边。
  做法:第一问很好求,重点在第二问。
       一开始做的时候是按60分写的(然而也写挂了),对于不用建边的两个元素,给它们之间连一条边,然后搜索共有多少个最长上升子序列,给其中的每个元素都打上标记,如果某个元素被标记的次数       和最长上升子序列的个数相等,则输出。
  正解:倒着循环一遍,如果某个元素的后面有比它大且在最长上升子序列中的元素,那么它也一定在最长上升子序列中。
       并且记录长度为i的在最长上升子序列中的序列段有几个。最后统计哪些元素在最长上升子序列中并且它那个长度只出现了一次。 
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 100010
using namespace std;
int a[N],q[N],f[N],maxx[N],ok[N],sum[N],n;
int main(){
    //freopen("bubble.in","r",stdin);
    //freopen("bubble.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    q[1]=a[1];f[1]=1;int len=1;
    for(int i=2;i<=n;i++){
        int pos=lower_bound(q+1,q+len+1,a[i])-q;
        if(pos>len){
            f[i]=len+1;q[++len]=a[i];
        }
        else {
            f[i]=pos;q[pos]=a[i];
        }
    }
    printf("%d\n",len);
    maxx[len+1]=N;
    for(int i=n;i>=1;i--){
        if(maxx[f[i]+1]>a[i]){
            ok[i]=true;sum[f[i]]++;
            maxx[f[i]]=max(maxx[f[i]],a[i]);
        }
    }
    for(int i=1;i<=n;i++){
        if(ok[i]&&sum[f[i]]==1)
            printf("%d ",i);
    }
    return 0;
}

 

推荐阅读