独立集

来源:互联网 发布:知乎黑名单 编辑:程序博客网 时间:2024/05/01 04:51

题目描述
有一天,一个名叫顺旺基的程序员从石头里诞生了。又有一天,他学会了冒泡排序和独立集。在一个图里,独立集就是一个点集,满足任意两个点之间没有边。于是他就想把这两个东西结合在一起。众所周知,独立集是需要一个图的。那么顺旺基同学创造了一个算法,从冒泡排序中产生一个无向图。
这个算法不标准的伪代码如下:
procedure bubblesortgraph(n, a[]) :
/*输入:点数n,1到n的全排列a。
输出:一个点数为n的无向图G。*/
创建一个有n个点,0条边的无向图G。
repeat
swapped = false
for i 从 1 到 n-1 :
if a[i] > a[i + 1] :
在G中连接点a[i]和点a[i + 1]
交换a[i]和a[i + 1]
swapped = true
until not swapped
输出图G。
//结束。
那么我们要算出这个无向图G最大独立集的大小。但是事情不止于此。顺旺基同学有时候心情会不爽,这个时候他就会要求你再回答多一个问题:最大独立集可能不是唯一的,但有些点是一定要选的,问哪些点一定会在最大独立集里。今天恰好他不爽,被他问到的同学就求助于你了。
输入
两行。第一行为N,第二行为1到N的一个全排列。

输出
两行。第一行输出最大独立集的大小,第二行从小到大输出一定在最大独立集的点的编号(输入时的序号)。
样例输入
3
3 1 2
样例输出
2
2 3
提示
【数据范围】
30%的数据满足 N<=16
60%的数据满足 N<=1,000
100%的数据满足 N<=100,000

多列几个数据,就可以发现最大独立集大小,就是最长不下降子序列大小。难点就是求一定在最长不下降子序列的元素。我们从1到n求一遍最长不下降子序列,从n到1做一遍最长不下降子序列。每次记录位置,如果两次位置相加为答案且这一位置只有这一个数,那么它就是。

varn,i,l,r,mid,len,m,num,j,v,tot,ii,ans:longint;a,d,b,dp,dp2,sum:array[0..200011] of longint;function max(a,b:longint):longint;begin  if a>b then exit(a) else exit(b);end;begin  readln(n);  for i:=1 to n do    read(a[i]);  for i:=1 to n do  begin    l:=0;    r:=len;    while l<>r do    begin      mid:=(l+r+1) div 2;      if d[mid]<a[i] then l:=mid                     else r:=mid-1;    end;    l:=l+1;    len:=max(len,l);    d[l]:=a[i];    dp[i]:=l;  end;  writeln(len);  ans:=len;  d[0]:=maxlongint;  len:=0;  for i:=n downto 1 do  begin    l:=0;    r:=len;    while l<>r do    begin      mid:=(l+r+1) div 2;      if d[mid]>a[i] then l:=mid                     else r:=mid-1;    end;    l:=l+1;    len:=max(len,l);    d[l]:=a[i];    dp2[i]:=dp[i]+l-1;    if dp2[i]=ans then sum[dp[i]]:=sum[dp[i]]+1;  end;  for i:=1 to n do  begin    if (dp2[i]=ans)and(sum[dp[i]]=1) then    begin      m:=m+1;      b[m]:=i;    end;  end;  for i:=1 to m do    if i<>m then write(b[i],' ') else write(b[i]);end.
0 0
原创粉丝点击