CERC 2012 J (拓扑排序)

题意:一些具有拓扑序的节点需要染色,这些节点一共分为两类。问你按照给出的拓扑顺序染色完结点最少需要多少次切换。

思路:我们按照拓扑排序的做法,建立两个栈分别存放两种不同种类的节点,每次把一个栈中的所有节点都处理完了才处理另一个,这样切换次数即为最终答案。

代码如下:

  1 /**************************************************
  2  * Author     : xiaohao Z
  3  * Blog     : http://www.cnblogs.com/shu-xiaohao/
  4  * Last modified : 2014-06-30 12:30
  5  * Filename     : cerc_j.cpp
  6  * Description     :
  7  * ************************************************/
  8
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <cmath>
 14 #include <algorithm>
 15 #include <queue>
 16 #include <stack>
 17 #include <vector>
 18 #include <set>
 19 #include <map>
 20 #define MP(a, b) make_pair(a, b)
 21 #define PB(a) push_back(a)
 22
 23 using namespace std;
 24 typedef long long ll;
 25 typedef pair<int, int> pii;
 26 typedef pair<unsigned int,unsigned int> puu;
 27 typedef pair<int, double> pid;
 28 typedef pair<ll, int> pli;
 29 typedef pair<int, ll> pil;
 30
 31 const int INF = 0x3f3f3f3f;
 32 const double eps = 1E-6;
 33 const int LEN = 100000+10;
 34 int n, m, vex[LEN], ind[LEN], tmp_ind[LEN];
 35 bool vis[LEN];
 36 struct E{
 37     int to, next;
 38 }edge[LEN*10];
 39 int head[LEN], top;
 40
 41 void init(){
 42     top = 0;
 43     memset(head, -1, sizeof head);
 44 }
 45
 46 void addedge(int u, int v){
 47     edge[top].next = head[u];
 48     edge[top].to = v;
 49     head[u] = top++;
 50 }
 51
 52 int solve(int flag){
 53     for(int i=0; i<n; i++)
 54         ind[i] = tmp_ind[i];
 55     memset(vis, 0, sizeof vis);
 56     queue<int> q1, q0;
 57     for(int i=0; i<n; i++){
 58         if(!ind[i]){
 59             vis[i] = 1;
 60             if(!vex[i]) q0.push(i);
 61             else q1.push(i);
 62         }
 63     }
 64     int ret = 0, cnt = 0;
 65     for(;;ret++){
 66         if(flag){
 67             if(q1.empty()) {
 68                 ret--; break;
 69             }
 70             while(!q1.empty()){
 71                 int nv = q1.front(); q1.pop();
 72                 cnt ++;
 73                 for(int i=head[nv]; i!=-1; i=edge[i].next){
 74                     int nx = edge[i].to;
 75                     ind[nx] --;
 76                     if(!ind[nx] && !vis[nx]){
 77                         vis[nx] = 1;
 78                         if(vex[nx]) q1.push(nx);
 79                         else q0.push(nx);
 80                     }
 81                 }
 82             }
 83         }else{
 84             if(q0.empty()) {
 85                 ret--; break;
 86             }
 87             while(!q0.empty()){
 88                 int nv = q0.front(); q0.pop();
 89                 cnt ++;
 90                 for(int i=head[nv]; i!=-1; i=edge[i].next){
 91                     int nx = edge[i].to;
 92                     ind[nx] --;
 93                     if(!ind[nx] && !vis[nx]){
 94                         vis[nx] = 1;
 95                         if(vex[nx]) q1.push(nx);
 96                         else q0.push(nx);
 97                     }
 98                 }
 99             }
100         }
101         flag = !flag;
102     }
103     if(cnt != n) return INF;
104     return ret;
105 }
106
107 int main()
108 {
109 //    freopen("in.txt", "r", stdin);
110
111     int a, b, T;
112     scanf("%d", &T);
113     while(T--){
114         init();
115         memset(tmp_ind, 0, sizeof tmp_ind);
116         scanf("%d%d", &n, &m);
117         for(int i=0; i<n; i++){
118             scanf("%d", &vex[i]);
119             vex[i] --;
120         }
121         for(int i=0; i<m; i++){
122             scanf("%d%d", &a, &b);
123             a--, b--;
124             addedge(a, b);
125             tmp_ind[b] ++;
126         }
127         int ans = min(solve(0), solve(1));
128         printf("%d\n", ans);
129     }
130     return 0;
131 }

CERC 2012 J (拓扑排序)

时间: 2024-08-26 03:04:30

CERC 2012 J (拓扑排序)的相关文章

【算法学习笔记】46.拓扑排序 优先队列 SJTU OJ 3010 Complicated Buttons

Description 凯恩在遗迹探险时遇到了n个按钮,刚开始所有按钮都处于开状态,凯恩的经验告诉他把所有按钮都关上会有“好事”发生,可是有些按钮按下时会让其他一些已经闭合的按钮弹开,经过凯恩研究,每个按钮都对应着一个固定的弹开集合,这个按钮按下时,弹开集合中所有的按钮都会变为开状态.现在小k想知道是否能让所有的按钮变为闭状态.如果能,打印最少步数以及方案,否则,打印“no solution”. Input Format 第一行一个整数n,表示n个按钮. 接下来n行,表示编号为1到n个按钮的弹开

HDU 4324 Triangle LOVE (拓扑排序)

Triangle LOVE Problem Description Recently, scientists find that there is love between any of two people. For example, between A and B, if A don't love B, then B must love A, vice versa. And there is no possibility that two people love each other, wh

hdu 4324 Triangle LOVE(拓扑排序)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4324 Triangle LOVE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 3858    Accepted Submission(s): 1516 Problem Description Recently, scientists f

hdu1285(拓扑排序)

这道题要求没有输赢关系的两个元素必须按照升序输出,有输赢关系的,赢得在输的前面,所以用队列或者栈来降低时间复杂度的优化过的拓扑排序会出错. 比如这组输入 5 3 1 2 2 3 4 5 至少我写的两种拓扑排序都wa了.但是不用队列或者栈来优化的话, 1.每次都从头至尾扫描一遍,找到一个没标记过的节点, 2.将它标记 3.然后删除从它出来的每条边. 重复这三个操作,加标记的次序,就是题目要的答案. 下面的代码中用到了队列,但只是用来保存答案而已.并没有用它优化的意思. #include <iost

uva 10305 Ordering Tasks(拓扑排序)

拓扑排序,不用判断是否有环,dfs挺简单的 代码: #include<stdio.h> #include<string.h> #include<stdlib.h> int map[105][105]; int visit[105]; int c[105]; int n,m,t; void dfs(int x) { visit[x] = 1; for(int i=1; i<=n; i++) { if(!visit[i]&&map[i][x]==1)

POJ1420 Spreadsheet(拓扑排序)注意的是超内存

Spreadsheet Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 617   Accepted: 290 Description In 1979, Dan Bricklin and Bob Frankston wrote VisiCalc, the first spreadsheet application. It became a huge success and, at that time, was the ki

拓扑排序之变量序列算法分析

拓扑排序之变量序列 巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo) 题目描述: 假设有n个变量(1<=n<=26,变量名用单个小写字母表示),还有m个二元组(u,v),分别表示变量u小于v.那么,所有变量从小到大排列起来应该是什么样子的呢? 例如有4个变量a,b,c,d,若以知a<b,c<b,d<c,则这4个变量的排序可能是a<d<c<b.尽管还有可能其他的可能,你只需找出其中的一个即可. 输入: 输入为一

UVALive 6467 Strahler Order 拓扑排序

这题是今天下午BNU SUMMER TRAINING的C题 是队友给的解题思路,用拓扑排序然后就可以了 最后是3A 其中两次RE竟然是因为: scanf("%d",mm); ORZ 以后能用CIN还是CIN吧 QAQ 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostre

【Luogu】P3116会议时间(拓扑排序,DP)

题目链接 本题使用拓扑排序来规划DP顺序.设s[i][j]表示i步是否能走到j这个点,e[i][j]表示i步是否能走到j这个点——用第二条路径.因为要满足无后效性和正确性,只有第i个点已经全部更新完毕的时候才能用它来更新其他的点.所以用拓扑. 代码如下 #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; inline long