poj-2230
2014-07-02 20:20
204 查看
//4388K 1719MS G++
#include <cstdio>
#include <cstring>
using namespace std;
#define MAX_M 2*50000 + 2
#define MAX_V 10000+2
struct Edge{
int to;
int next;
};
typedef struct Edge Edge;
int graph[MAX_V];
Edge edges[MAX_M];
char edgePassedTime[MAX_M];
int edgeFreeSlot = 1;
int totalEdgePassTime = 0;
int N;
int M;
char dfs(int vetexId) {
// printf("dfs %d\n", vetexId);
int curEdge = graph[vetexId]; // get first vetex from this edge
while(curEdge) {
// printf("for %d, -> %d\n", vetexId, edges[curEdge].to);
if (!edgePassedTime[curEdge]) { // this edge can pass
edgePassedTime[curEdge] = 1; // pass this edge, edge pass time + 1
totalEdgePassTime++; // total edge pass time also + 1
dfs(edges[curEdge].to);
// if (dfs(edges[curEdge].to)) { // if pass this edge is OK, return success.
// path.push(edges[curEdge]);
// printf("%d -> %d\n", vetexId, edges[curEdge].to);
// printf("%d\n", edges[curEdge].to);
// return 1;
// } else { // if this edge is OK, try next edge, and retore the edge's pass time.
// edgePassedTime[curEdge] = 0;
// totalEdgePassTime--;
// }
}
curEdge = edges[curEdge].next; // curEdge is not OK, try next edge.
}
printf("%d\n", vetexId);
return 0;
// return totalEdgePassTime == M*2; // if all edge has been passed 2 times. or all edge from this vetex is not OK. return fail.
}
int main() {
N = 0;
M = 0;
scanf("%d %d", &N, &M);
if (!N || !M) {
return 0;
}
memset(edgePassedTime, 0, sizeof(edgePassedTime));
memset(graph, 0, sizeof(graph));
memset(edges, 0, sizeof(edges));
edgeFreeSlot = 1;
totalEdgePassTime = 0;
// path.clear();
for (int i = 0; i < M; i++) {
int begin = 0;
int end = 0;
scanf("%d %d", &begin, &end);
if (graph[begin]) { // vetex has some edges before
int insertedSlotId = graph[begin]; // append new edge in first location, tail the before edges.
graph[begin] = edgeFreeSlot;
edges[edgeFreeSlot].next = insertedSlotId;
edges[edgeFreeSlot].to = end;
} else { // first edge
graph[begin] = edgeFreeSlot; // no prev edge
edges[edgeFreeSlot].next = 0;
edges[edgeFreeSlot].to = end;
}
edgeFreeSlot++;
if (graph[end]) { // vetex has some edges before
int insertedSlotId = graph[end]; // append new edge in first location, tail the before edges.
graph[end] = edgeFreeSlot;
edges[edgeFreeSlot].next = insertedSlotId;
edges[edgeFreeSlot].to = begin;
} else { // first edge
graph[end] = edgeFreeSlot; // no prev edge
edges[edgeFreeSlot].next = 0;
edges[edgeFreeSlot].to = begin;
}
edgeFreeSlot++;
}
dfs(1);
// printf("1\n");
}
4388K 1719MS G++
同样的欧拉路题,不过题目说的有点隐晦,即每一条路径要正好经过两次,
初看会有点摸不着头脑,不过从有向图的角度分析就很好理解了,即如果A与B中间有一个path,
那么可以将这个path看做有向图的两个path, 即 A->B 和 B->A, 那么这道题就转为了求有向图欧拉路(每条有向边都经过一次,两条相对的边都经过就相当于经过原来边两次了), 因为在这个有向图中每个点的出度与入度都相等(因为一个path对应一个出度和一个入度),所以欧拉回路必存在,并且起点可以是任何一个点(这样就能从1开始了,题目为了方便求解,做了很多前提)。
那么下一步就是求出这个欧拉回路的路径了,首先因为点太多了(10000),因此,用邻接矩阵表示是不行的,只能使用邻接矩阵了,一般的邻接矩阵表示法都是
每个点维护一串链表,标示与其连通的点,在ACM题中,碰上这种情况,一般都不会现场的malloc内存,速度太慢,还是按照之前静态hash表和tire树的做法,
预先分配一个大内存数组A(数组大小就是边的数量*2,因为一条无向边变为两个有向边),而指针则用保存此数组某个位置的变量来模拟,如同code里面的,首先要有一个数组S,该数组对应于每一个点N,数组保存的是与其相接的点N1
在A中的位置,而A除了保存该点的id外,还维护一个next变量,保存的是下一个与N相接的点N2在A中的位置,同样N2还会维护N3的位置...,直到最后一个邻接的点Nx,其next为-1,表示这是最后一个邻接点了。
这样就能在使用邻接表的同时,又维护高效率,这种预先分配内存池+位置模拟指针的做法,对模拟那些只增加,增加以后不会改变或者删除的指针数据结构,是很适合的,只是如果要删除元素的话,就比较麻烦了。
接下来就是不断的读取输入,然后构造静态邻接表了,注意的是,虽然输入的只有一条 A 连通 B, 但是因为是按照有向图的思路来的,所以这条 A连通B其实是两条信息:
A能到B B能到A, 这样就要在静态邻接表里分别对 A 和B进行相应的增加, 一开始2B了, 每次某个点N有新的联通点Nx时,都遍历一遍N的邻接点链表,跑到最后把Nx加上,结果TLE,因为根本不需要,只需要现为Nx在大数组A中取得一个空闲位置H(一般空闲位置都是从1递增的,分出一个空闲index+1)把点数组S
直接等于此H,而Nx的next则指向原来的N的第一个邻接点的在大数组A中位置即可,这样就把新的点加入了。
邻接表构造完了,就可以用DFS方式来取得路径了(这一块其实还不是非常清楚,要在以后的DFS/BFS题中深化),维护一个边的flag数组来标示此边是否被经过,这里如果用普通的二维矩阵表示,也不行(10000*10000),还是开一个一维数组F(和大数组A大小一样)来保存每条边的状态,之所以一维能达到目的,是因为在之前的向大数组A中加入边的过程中,每条边已经有了自己的id了(就是在大数组的位置),而邻接表的next则正好保存此位置,即根据邻接表的某个点的某条边,可以确定该边在F的位置。
有了F以后,就可以DFS了,从1(题目要求)开始遍历每条边(因为题目已经保证了解必定存在,因此每遍历到一点,输出该点,最后就一定是要求的路径),每遍历一条,就F相应=1.直到最后所有的边都被遍历(这也是一个有意思的地方,一般都是遍历所有的点,但在这里成了遍历所有的边)。
#include <cstdio>
#include <cstring>
using namespace std;
#define MAX_M 2*50000 + 2
#define MAX_V 10000+2
struct Edge{
int to;
int next;
};
typedef struct Edge Edge;
int graph[MAX_V];
Edge edges[MAX_M];
char edgePassedTime[MAX_M];
int edgeFreeSlot = 1;
int totalEdgePassTime = 0;
int N;
int M;
char dfs(int vetexId) {
// printf("dfs %d\n", vetexId);
int curEdge = graph[vetexId]; // get first vetex from this edge
while(curEdge) {
// printf("for %d, -> %d\n", vetexId, edges[curEdge].to);
if (!edgePassedTime[curEdge]) { // this edge can pass
edgePassedTime[curEdge] = 1; // pass this edge, edge pass time + 1
totalEdgePassTime++; // total edge pass time also + 1
dfs(edges[curEdge].to);
// if (dfs(edges[curEdge].to)) { // if pass this edge is OK, return success.
// path.push(edges[curEdge]);
// printf("%d -> %d\n", vetexId, edges[curEdge].to);
// printf("%d\n", edges[curEdge].to);
// return 1;
// } else { // if this edge is OK, try next edge, and retore the edge's pass time.
// edgePassedTime[curEdge] = 0;
// totalEdgePassTime--;
// }
}
curEdge = edges[curEdge].next; // curEdge is not OK, try next edge.
}
printf("%d\n", vetexId);
return 0;
// return totalEdgePassTime == M*2; // if all edge has been passed 2 times. or all edge from this vetex is not OK. return fail.
}
int main() {
N = 0;
M = 0;
scanf("%d %d", &N, &M);
if (!N || !M) {
return 0;
}
memset(edgePassedTime, 0, sizeof(edgePassedTime));
memset(graph, 0, sizeof(graph));
memset(edges, 0, sizeof(edges));
edgeFreeSlot = 1;
totalEdgePassTime = 0;
// path.clear();
for (int i = 0; i < M; i++) {
int begin = 0;
int end = 0;
scanf("%d %d", &begin, &end);
if (graph[begin]) { // vetex has some edges before
int insertedSlotId = graph[begin]; // append new edge in first location, tail the before edges.
graph[begin] = edgeFreeSlot;
edges[edgeFreeSlot].next = insertedSlotId;
edges[edgeFreeSlot].to = end;
} else { // first edge
graph[begin] = edgeFreeSlot; // no prev edge
edges[edgeFreeSlot].next = 0;
edges[edgeFreeSlot].to = end;
}
edgeFreeSlot++;
if (graph[end]) { // vetex has some edges before
int insertedSlotId = graph[end]; // append new edge in first location, tail the before edges.
graph[end] = edgeFreeSlot;
edges[edgeFreeSlot].next = insertedSlotId;
edges[edgeFreeSlot].to = begin;
} else { // first edge
graph[end] = edgeFreeSlot; // no prev edge
edges[edgeFreeSlot].next = 0;
edges[edgeFreeSlot].to = begin;
}
edgeFreeSlot++;
}
dfs(1);
// printf("1\n");
}
4388K 1719MS G++
同样的欧拉路题,不过题目说的有点隐晦,即每一条路径要正好经过两次,
初看会有点摸不着头脑,不过从有向图的角度分析就很好理解了,即如果A与B中间有一个path,
那么可以将这个path看做有向图的两个path, 即 A->B 和 B->A, 那么这道题就转为了求有向图欧拉路(每条有向边都经过一次,两条相对的边都经过就相当于经过原来边两次了), 因为在这个有向图中每个点的出度与入度都相等(因为一个path对应一个出度和一个入度),所以欧拉回路必存在,并且起点可以是任何一个点(这样就能从1开始了,题目为了方便求解,做了很多前提)。
那么下一步就是求出这个欧拉回路的路径了,首先因为点太多了(10000),因此,用邻接矩阵表示是不行的,只能使用邻接矩阵了,一般的邻接矩阵表示法都是
每个点维护一串链表,标示与其连通的点,在ACM题中,碰上这种情况,一般都不会现场的malloc内存,速度太慢,还是按照之前静态hash表和tire树的做法,
预先分配一个大内存数组A(数组大小就是边的数量*2,因为一条无向边变为两个有向边),而指针则用保存此数组某个位置的变量来模拟,如同code里面的,首先要有一个数组S,该数组对应于每一个点N,数组保存的是与其相接的点N1
在A中的位置,而A除了保存该点的id外,还维护一个next变量,保存的是下一个与N相接的点N2在A中的位置,同样N2还会维护N3的位置...,直到最后一个邻接的点Nx,其next为-1,表示这是最后一个邻接点了。
这样就能在使用邻接表的同时,又维护高效率,这种预先分配内存池+位置模拟指针的做法,对模拟那些只增加,增加以后不会改变或者删除的指针数据结构,是很适合的,只是如果要删除元素的话,就比较麻烦了。
接下来就是不断的读取输入,然后构造静态邻接表了,注意的是,虽然输入的只有一条 A 连通 B, 但是因为是按照有向图的思路来的,所以这条 A连通B其实是两条信息:
A能到B B能到A, 这样就要在静态邻接表里分别对 A 和B进行相应的增加, 一开始2B了, 每次某个点N有新的联通点Nx时,都遍历一遍N的邻接点链表,跑到最后把Nx加上,结果TLE,因为根本不需要,只需要现为Nx在大数组A中取得一个空闲位置H(一般空闲位置都是从1递增的,分出一个空闲index+1)把点数组S
直接等于此H,而Nx的next则指向原来的N的第一个邻接点的在大数组A中位置即可,这样就把新的点加入了。
邻接表构造完了,就可以用DFS方式来取得路径了(这一块其实还不是非常清楚,要在以后的DFS/BFS题中深化),维护一个边的flag数组来标示此边是否被经过,这里如果用普通的二维矩阵表示,也不行(10000*10000),还是开一个一维数组F(和大数组A大小一样)来保存每条边的状态,之所以一维能达到目的,是因为在之前的向大数组A中加入边的过程中,每条边已经有了自己的id了(就是在大数组的位置),而邻接表的next则正好保存此位置,即根据邻接表的某个点的某条边,可以确定该边在F的位置。
有了F以后,就可以DFS了,从1(题目要求)开始遍历每条边(因为题目已经保证了解必定存在,因此每遍历到一点,输出该点,最后就一定是要求的路径),每遍历一条,就F相应=1.直到最后所有的边都被遍历(这也是一个有意思的地方,一般都是遍历所有的点,但在这里成了遍历所有的边)。
相关文章推荐
- poj[2230]Watchcow 深搜 欧拉回路
- POJ - 2230 Watchcow(欧拉回路+dfs输出路径)
- 【欧拉回路】poj 2230 Watchcow
- poj[2230]Watchcow 深搜 欧拉回路
- POJ 2230 Watchcow 欧拉回路
- POJ 2230 欧拉回路变型
- poj 2230 欧拉回路
- POJ2230 Watchcow【欧拉回路】
- poj 2230 Watchcow(有向图的欧拉回路)
- poj 2230——Watchcow
- poj 2230详解
- POJ - 2230 (欧拉回路)
- POJ ~ 2230 ~ Watchcow(欧拉回路)
- POJ 2230 (欧拉路)
- poj 2230 Watchcow
- Poj 2230 Watchcow (欧拉回路)打印欧拉回路路径
- POJ2230题解
- POJ 2230 Watchcow(欧拉回路+DFS)
- POJ 2230 Watchcow (欧拉回路)
- poj 2230 Watchcow