拓扑排序
来源:互联网 发布:wampserver配置sql 编辑:程序博客网 时间:2024/06/07 01:05
1、hdu 4324
题目要求假如a到b没有边,那么b到a一定有边,且两点之间只可能有一条边。根据这个要求,我们可以知道,只要图中存在环,那么就一定存在3元环。那么,只要用拓扑排序删除入度为0的节点,计算剩下的节点就可以了。
2、hdu 2647
反向建边,要注意的是,如果a -> b,c -> b,那么要从a和c中选择一个最大的。这里点太多,需要用邻接表来表示。
3、hdu 4109
跟hdu 2647题相似,不用反向建边,一个结点的时间,是所有与其相接的边的头结点(u - > v,u为头,v为尾)的时间加上它的安全距离的最大值。
4、hdu 1285 3342 2094
模板题
5、hdu 2497
这题是单纯的拓扑排序,但是数据量太大,点和边数最大都有100W,首先需要用邻接表来存储。第一次提交时用了下面这段代码,超时。
void sort(){ for(int i = 1;i <= vertex;i++) { int j = 1; while(j <= vertex && indegree[j]) j++; if(j > vertex) { puts("IMPOSSIBLE"); return; } indegree[j]--; result[i] = j; j = head[j]; while(j != -1) { indegree[adjlist[j].v]--; j = adjlist[j].next; } } for(int i = 1;i <= vertex;i++) printf("%d\n",result[i]);}外层循环一定是vertex(点的个数)次,再看内层循环,找入度为0的点,每次都需要遍历indegree[]数组,只要数据强一点,那么几乎需要vertex * vertex的时间。所以,这里可以用队列优化一下。将入度为0的点入队,那么找入度为0的点的操作就可以在O(1)内完成。
void sort(){ while(!Q.empty()) Q.pop(); for(int i = 1;i <= vertex;i++) if(!indegree[i]) Q.push(i); for(int i = 1;i <= vertex;i++) { int j; if(Q.empty()) { puts("IMPOSSIBLE"); return; } j = Q.front(); Q.pop(); indegree[j]--; result[i] = j; j = head[j]; while(j != -1) { indegree[adjlist[j].v]--; if(!indegree[adjlist[j].v]) Q.push(adjlist[j].v); j = adjlist[j].next; } } for(int i = 1;i <= vertex;i++) printf("%d\n",result[i]);}另外,求拓扑排序还有深搜的方法。《算法导论》上有段伪代码,写明了对于有向无环图求拓扑排序的方法:每次深搜一个未访问的结点,点出栈顺序的逆顺就是我们所求的拓扑排序。但现在的问题是,我们的图可能是有环的,那么,用深搜怎么判断有环?其实,《算法导论》也给我们指明了方法:在深搜时,我们可以用访问的结点进行染色:初始时,所有结点都是白色的,在搜索一个点时,首先将这个点染成灰色,然后在出栈(即这个点DFS结束时)时将这个点染成黑色。按这种方法,如果当前的点跟接下来要访问的点的颜色相同,那么就说明是有环的。用深搜的话,每个点只访问一次,每条边也只访问一次,所以时间复杂度为O(v + e)。
int head[N],result[N],indegree[N],visited[N];queue<int> Q;struct Node{ int next; int v; Node(){}; Node(int a,int b):next(a),v(b){}}adjlist[N];struct Graph_Topology{ int vertex,edge,num; bool circle; int flag; void init(int n) { vertex = n,edge = 0; memset(indegree,0,sizeof(indegree)); memset(visited,0,sizeof(visited)); for(int i = 0;i <= vertex;i++) head[i] = -1; num = 0; circle = false; } void insert(int u,int v) { /* int i; for(i = head[u];i != -1;i = adjlist[i].next) if(adjlist[i].v == v) break; if(i != -1) return; */ adjlist[edge] = Node(head[u],v); head[u] = edge++; indegree[v]++; } void sort() { while(!Q.empty()) Q.pop(); for(int i = 1;i <= vertex;i++) if(!indegree[i]) Q.push(i); for(int i = 1;i <= vertex;i++) { int j; if(Q.empty()) { puts("IMPOSSIBLE"); return; } j = Q.front(); Q.pop(); indegree[j]--; result[i] = j; j = head[j]; while(j != -1) { indegree[adjlist[j].v]--; if(!indegree[adjlist[j].v]) Q.push(adjlist[j].v); j = adjlist[j].next; } } for(int i = 1;i <= vertex;i++) printf("%d\n",result[i]); } void DFS() { for(int i = 1;i <= vertex;i++) if(!visited[i]) { //flag = i; DFS_Visit(i); if(circle) { puts("IMPOSSIBLE"); return; } } for(int i = num;i >= 1;i--) printf("%d\n",result[i]); } void DFS_Visit(int x) { if(circle) return; visited[x] = GREY; for(int i = head[x];i != -1;i = adjlist[i].next) if(!visited[adjlist[i].v]) DFS_Visit(adjlist[i].v); else if(visited[adjlist[i].v] == visited[x]) { circle = true; return; } visited[x] = BLACK; result[++num] = x; }};6、hdu 1811
对相等的边合并成一个点,并用这个点进行拓扑排序的计算。
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 【拓扑排序】
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 拓扑排序
- 使用BitBlt复制位图,出现显示黑色块的问题
- the+比较级,the+比较级
- 初识Objecive-C 之 键值编码(KVC)
- 利用存儲過程分頁
- TortoiseSVN使用简介
- 拓扑排序
- jquery源码阅读知识储备(4)关于js中if的解惑
- Android 怎样在styles.xml中定义自己的样式并引用样式
- 原始类型与封装类的区别
- servlet实现文件上传
- 三星SMDK4412的烧写镜像
- Tomcat server.xml笔记
- 文件夹选项为什么没有了共享一页?
- Android Fragment实践(二)