2017.3.3 双栈排序 失败总结

来源:互联网 发布:女生学金融 知乎 编辑:程序博客网 时间:2024/06/11 17:02

   这道题虽然是noip的题,但还是很能反映你思维水平的、 

   说出来二分图、黑白染色对于一个oier来说肯定不陌生,有的人很快就能说出做法,写出程序。

   但是一出成题怎么就不会了呢?

     其实主要失误在于 我是站在选A、B的角度思考问题的,但实际上,如果思路足够清晰,还是能回到互斥的角度的

    因为如果站在选A选B的角度上,能影响当前决策的实际上有3个不同的因素,1是出现顺序,这好办,扫过去就行。2是当前栈中元素的影响(这实际上是有后效性的,因为后面的数也会对当前决策造成影响:后面小数卡大数,导致空间被浪费,同时贪心是错的:不信用7251463 试试、),3是当前数消不消除的影响。。(这比较坑,但如果从第2点已经看出后效性的话已经证实至少不是1个dp解决问题的题了)





这时候应该敏锐地发现,这种后效性是由空间消耗造成的,因为我们的贪心实际上维护的是一个尽量装A的序列,如果是跳着从大到小的序列,那对A的空间利用极低。

(ps:最讨厌分析中的“不妨”,这俩字没有任何意义,,解题的每一步都应该在题目中有根据的,用“不妨”蒙混过关对自己的思维并没有太大的帮助)

当然,对于能处理的情况,我们首选A列,那么我们应该还是用dp来维护,但并不完成划分A、B工作,只是把能放在一个栈里的区间求出来,

然后由于非A即B,就需要利用黑白染色的互斥原理,进行遍历。


总结:这题分析不出来,主要是思路受尽量选A的条件制约,抓住贪心放不开,认为前几个都应该放A里,且忽略了可行性这一重要因素,可行性是受尽量选A影响的。

应建立在可行性上尽量选A,而不是在尽量选A中实现可行性。


补一下,个人感觉第一步的dp也挺难的、

     可以从小的数据入手:

        1 2 3     :肯定可以单栈;                               1 3 2   :肯定可以单栈                          2 1 3    肯定可以单栈                  2 3 1:肯定不可以单栈(需要分开,且一定是2和3分开)

      3 1 2   :肯定可以单栈                                3 2 1     肯定可以单栈

     这样就考虑了退出的情况,强行装,为什么不会出现不可行的情况?因为不可装只和弹出、装入有关,现在dp考虑了出栈,如果在加上弹出的情况,A装不下了,那就是无论如何也装不下了,只能另寻栈。


#include<iostream>#include<cstdio>using namespace std;int n,woc,a[99999],i,j,l,stacka[99998],stackb[99999],topa,topb,tu[1999][1999],sta[1999],ru[1999];bool keyi,zou[1999];void dfs(int now){if(keyi==0)return ;for(int i=1;i<=n;i++){   if(zou[i])continue;if(tu[i][now]||tu[now][i]){if((sta[now]==1&&sta[i]==1)||(sta[now]==2&&sta[i]==2)){keyi=0;   return ;}if(sta[now]==1&&sta[i]==-1)sta[i]=2;if(sta[now]==2&&sta[i]==-1)sta[i]=1;zou[i]=1;dfs(i);}}}int main(){scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=1;i<=n;i++)for(j=i+1;j<=n;j++){if(a[i]>a[j])continue;for(l=j+1;l<=n;l++){if(a[l]<a[i]&&a[l]<a[j]){tu[j][i]=1;ru[i]++;ru[j]++;}}}for(i=1;i<=n;i++)if(ru[i]>0)sta[i]=-1;else sta[i]=1;keyi=1;for(i=1;i<=n;i++){if(ru[i]==1&&sta[i]==-1){sta[i]=1;zou[i]=1;dfs(i);        }}for(i=1;i<=n;i++)if(sta[i]==-1)keyi=0;if(!keyi){cout<<0;return 0;}stacka[0]=99999;stackb[0]=99999;woc=1;for(i=1;i<=n;i++){if(sta[i]==1){while(stacka[topa]<a[i]){if(stacka[topa]==woc){topa--;printf("b ");}else{   topb--;printf("d ");}woc++;}printf("a ");             stacka[++topa]=a[i];}else {while(stacka[topa]==woc){topa--;printf("b ");woc++;}while(stackb[topb]<a[i]){if(stacka[topa]==woc){   topa--;printf("b ");}else{   topb--;printf("d ");}woc++;}  stackb[++topb]=a[i];printf("c "); } }for(i=woc;i<=n;i++){if(stacka[topa]==i){printf("b ");--topa;}else {printf("d ");--topb;}}}



     

0 0
原创粉丝点击