【noip2008】双栈排序

题解:

对于任意一对ij (i<j) 如果存在k (k>j) 使得a[k]<a[i]<a[j] ij连线

表示ij不能在同一个栈

连完后对这个图做二分图染色 如果不能染色则无解

染完色后若颜色为0就表示该点会放在第一个栈 否则在第二个栈

知道每个点在哪个栈后 就能直接模拟了- -

 

证明:

命题:对于任意一对ij (i<j) 如果存在k (k>j) 使得a[k]<a[i]<a[j],是ij不在同一个栈的充分必要条件

所谓充分必要条件就是

若满足命题则ij必不能在一个栈 且若不满足命题 ij能在同一个栈

 

先证明若满足命题则ij必不能在一个栈:

因为弹出顺序要有序 所以 当j要进栈时i还没出栈(因为有a[k]<a[i] k还没出栈 )

a[i]<a[j] 所以这时j不能进栈

 

再证明若不满足命题 ij能在同一个栈:

不满足命题有两种情况

1.不存在i<j a[i]<a[j]

2.对任意ijk (i<j<k) a[j]<a[i] 且 a[j]<a[k]

 

情况这是个降序序列 显然能放进同一个栈

情况j要进栈时 显然i已经被弹出或能被弹出了 因为j后面没有比a[i]小的数

      所以i不会对j产生影响

 

代码:

 1 #include <cstdio>

 2 #include <cstdlib>

 3 const int N=1001,M=2000001;

 4 struct inli{

 5     int next,data;

 6     inli(const int a=0,const int b=0):

 7         next(a),data(b){}

 8 }line[M];

 9 int n,a[N],col[N],son[N],sta1[N],sta2[N],top1,top2,last[N],nl;

10 void makeline(){

11     for (int i=1;i<=n;i++){

12         int k=i;

13         for (int j=i+1;j<=n;j++)

14         if (a[j]<a[i]) k=j;

15         last[i]=k;

16         for (int j=i+1;j<k;j++)

17         if (a[j]>a[i]){

18             line[++nl]=inli(son[i],j),son[i]=nl;

19             line[++nl]=inli(son[j],i),son[j]=nl;

20         }

21     }

22 }

23 void print(){

24     puts("0");

25     exit(0);

26 }

27 void search(int t){

28     for (int i=son[t];i;i=line[i].next)

29     if (!col[line[i].data]){

30         col[line[i].data]=-col[t];

31         search(line[i].data);

32     }else if (col[t]==col[line[i].data])

33     print();

34 }

35 void makecol(){

36     for (int i=1;i<=n;i++)

37     if (!col[i]){

38         col[i]=1;

39         search(i);

40     }

41 }

42 void push1(int t){

43     printf("a ");

44     sta1[++top1]=t;

45 }

46 void pop1(){

47     printf("b ");

48     --top1;

49 }

50 void push2(int t){

51     printf("c ");

52     sta2[++top2]=t;

53 }

54 void pop2(){

55     printf("d ");

56     --top2;

57 }

58 void work(){

59     for (int i=1;i<=n;i++)

60     if (col[i]==1){

61         while (top1 && a[sta1[top1]]<a[i]) pop1();

62         push1(i);

63     }else{

64         while (top1 && last[sta1[top1]]<i) pop1();

65         while (top2 && a[sta2[top2]]<a[i]) pop2();

66         push2(i);

67     }

68     while (top1 || top2){

69         if (!top1) pop2();

70         else if (!top2) pop1();

71         else if (a[sta1[top1]]<a[sta2[top2]]) pop1();

72         else pop2();

73     }

74 }

75 int main(){

76     scanf("%d",&n);

77     for (int i=1;i<=n;i++) scanf("%d",&a[i]);

78     makeline();

79     makecol();

80     work();

81     puts("");

82 }
View Code

 

你可能感兴趣的:(2008)