zoukankan      html  css  js  c++  java
  • 【NOIP2008提高组T4】双栈排序-二分图染色

    测试地址:双栈排序

    做法:这题的做法比较难想,本人也是看了题解才懂。我们来研究两个元素num[i]和num[j]不能被存在同一个栈内的充要条件是什么。这个条件是:存在一个k,使得i<j<k而且num[k]<num[i]<num[j]。先来证充分性,即满足该条件则这两个元素一定不能被存在一个栈中。显然,num[k]要比num[i]先输出,然而弹出num[k]后,一定会先弹出num[j],又因为num[i]<num[j],所以矛盾。再来证必要性,即不满足该条件则这两个元素一定能被存在一个栈中。两种情况:1.对于所有的i<j<k,如果num[i]<num[j],有num[i]<num[k]。2.对于所有的i<j,num[i]>num[j]。第二种情况易看出是一个降序序列,肯定能被存在一个栈中。那么对于第一种情况,因为i<k,num[i]<num[k],所以num[i]先弹出了,而num[k]不会对num[j]产生影响。原因:如果num[j]<num[k],由于该情况中不存在一个r使得j<k<r且num[r]<num[j]<num[k],所以没有影响。如果num[j]<num[k],显然也没有影响。

    于是,我们对于所有满足条件的(i,j)之间连边,由于连边的两边一定存在不同的栈里,我们发现这和二分图的性质等价。于是,我们就用染色的方法证明这是不是一个二分图,如果不是即无解。对于一个连通分量(i,j,k,...)(i<j<k<...),将num[i]存在S1中是最优的,字典序最小。然后我们只需模拟入栈出栈的过程来输出操作序列即可。

    代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <stack>
    using namespace std;
    stack<int> s1,s2;
    int n,num[1010];
    int g[1010][1010]={0},color[1010]={0};
    int small[1010]={0};
    bool flag=0;
    
    void dfs(int u,int f)
    {
      if (color[u]==color[f]) flag=1;
      else if (!color[u])
      {
        color[u]=color[f]==1?2:1;
    	for(int i=1;i<=n;i++)
    	  if (g[u][i]) dfs(i,u);
      }
    }
    
    void color_g()
    {
      for(int i=1;i<=n;i++)
        if (!color[i])
    	{
    	  color[i]=1;
    	  for(int j=1;j<=n;j++)
    	  {
    	    if (g[i][j]) dfs(j,i);
    		if (flag) break;
    	  }
    	  if (flag) break;
    	}
    }
    
    int main()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
      
      for(int i=1;i<=n;i++)
        for(int j=n;j>i;j--)
    	  if (num[j]<num[i]) {small[i]=j;break;}
      
      for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
    	  if (num[i]<num[j]&&small[i]>j) g[i][j]=g[j][i]=1;
      
      color_g();
      
      if (flag) {printf("0");return 0;}
      
      int now=1;
      for(int i=1;i<=n;i++)
      {
        if (color[i]==1) s1.push(num[i]),printf("a ");
    	else s2.push(num[i]),printf("c ");
    	while(!s1.empty()||!s2.empty())
    	{
    	  int top1=s1.empty()?0:s1.top(),top2=s2.empty()?0:s2.top();
    	  if (top1==now) s1.pop(),now++,printf("b ");
    	  else if (top2==now) s2.pop(),now++,printf("d ");
    	       else break;
        }
      }
      
      return 0;
    }

  • 相关阅读:
    1442. Count Triplets That Can Form Two Arrays of Equal XOR
    1441. Build an Array With Stack Operations
    312. Burst Balloons
    367. Valid Perfect Square
    307. Range Sum Query
    1232. Check If It Is a Straight Line
    993. Cousins in Binary Tree
    1436. Destination City
    476. Number Complement
    383. Ransom Note
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793877.html
Copyright © 2011-2022 走看看