您的位置:首页 > 其它

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.直到最后所有的边都被遍历(这也是一个有意思的地方,一般都是遍历所有的点,但在这里成了遍历所有的边)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: