vijos 1605 双栈排序 - 贪心 - 二分图
Posted yyf0309
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vijos 1605 双栈排序 - 贪心 - 二分图相关的知识,希望对你有一定的参考价值。
不能发现两个数$a_{j}, a_{k} (j < k)$不能放在同一个栈的充分必要条件时存在一个$i$使得$j < k < i$且$a_{i} < a_{j} < a_{k}$。
证明?写个dfs就证完了(就是考虑任意一个三元组)。
然后可建图,对于满足上面条件的$(j, k)$,$j$和$k$连一条无向边。
显然必要条件时图不存在奇环,即能够二分染色。
再证明一下这是必要条件。
我们先构造一个做法:硬点二分染色完白点扔第一个栈里,黑点扔第二个栈里,当当前需要输出的数能够输出的时候就输出,否则继续加数。
我们只需要证明每个数都能被正确的输出就行了。
显然第1个数一定能被正确地输出。
假设前$k - 1 (k > 1)$个数已经被正确地输出了,考虑第$k$个数。
- 第$k$个数不在栈中,那么还剩在序列中,我们把之间的数加入栈中,再把它加入弹出,它就正确地输出了。
- 第$k$个数在栈中
- 某个栈的栈顶,直接弹出,正确地输出了。
- 否则它上面一定存在一个数$x > k$使得它无法弹出。
- 如果$1, 2, dots, k - 1$中都在$k$之前,那么输出完前$k - 1$个数后,$k$入栈后就可以弹出并输出了,与做法矛盾。
- 否则存在一个$y < x$在$k$之后,由建图方法和染色可知$k, x$不能在同一个栈中,矛盾。
因此图能够二分染色是存在解的充分必要条件。
然后拿个栈直接贪心就好了。每次选择能够进行的字典序最小的操作。
Code
1 /** 2 * Vijos 3 * Problem#1605 4 * Accepted 5 * Time: 42ms 6 * Memory: 1.363m 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstring> 11 #include <cstdio> 12 using namespace std; 13 typedef bool boolean; 14 15 const int N = 1e3 + 5; 16 17 int n; 18 int ar[N]; 19 int mns[N]; 20 boolean g[N][N]; 21 22 inline void init() { 23 scanf("%d", &n); 24 for (int i = 1; i <= n; i++) 25 scanf("%d", ar + i); 26 } 27 28 int col[N]; 29 boolean color(int p, int col) { 30 if (::col[p] != -1) 31 return ::col[p] == col; 32 ::col[p] = col; 33 for (int i = 1; i <= n; i++) 34 if (g[p][i] && !color(i, col ^ 1)) 35 return false; 36 return true; 37 } 38 39 int s1[N], s2[N]; 40 int tp1, tp2; 41 42 inline void solve() { 43 mns[n] = ar[n]; 44 for (int i = n - 1; i; i--) 45 mns[i] = min(mns[i + 1], ar[i]); 46 for (int i = 1; i < n; i++) 47 for (int j = i + 1; j < n; j++) 48 if (ar[i] < ar[j] && mns[j] < ar[i]) 49 g[i][j] = g[j][i] = true; 50 memset(col, -1, sizeof(col)); 51 for (int i = 1; i <= n; i++) 52 if (col[i] == -1 && !color(i, 0)) { 53 puts("0"); 54 return; 55 } 56 57 int cur = 1, p = 1; 58 while (cur <= n) { 59 if (p <= n && !col[p] && s1[tp1] != cur) 60 putchar(‘a‘), s1[++tp1] = ar[p++]; 61 else if (s1[tp1] == cur) 62 putchar(‘b‘), tp1--, cur++; 63 else if (p <= n && col[p] && s2[tp2] != cur) 64 putchar(‘c‘), s2[++tp2] = ar[p++]; 65 else 66 putchar(‘d‘), tp2--, cur++; 67 putchar(‘ ‘); 68 } 69 } 70 71 int main() { 72 init(); 73 solve(); 74 return 0; 75 }
以上是关于vijos 1605 双栈排序 - 贪心 - 二分图的主要内容,如果未能解决你的问题,请参考以下文章