poj-2230

//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[N]直接等于此H,而Nx的next则指向原来的N的第一个邻接点的在大数组A中位置即可,这样就把新的点加入了。

邻接表构造完了,就可以用DFS方式来取得路径了(这一块其实还不是非常清楚,要在以后的DFS/BFS题中深化),维护一个边的flag数组来标示此边是否被经过,这里如果用普通的二维矩阵表示,也不行(10000*10000),还是开一个一维数组F(和大数组A大小一样)来保存每条边的状态,之所以一维能达到目的,是因为在之前的向大数组A中加入边的过程中,每条边已经有了自己的id了(就是在大数组的位置),而邻接表的next则正好保存此位置,即根据邻接表的某个点的某条边,可以确定该边在F的位置。

有了F以后,就可以DFS了,从1(题目要求)开始遍历每条边(因为题目已经保证了解必定存在,因此每遍历到一点,输出该点,最后就一定是要求的路径),每遍历一条,就F相应=1.直到最后所有的边都被遍历(这也是一个有意思的地方,一般都是遍历所有的点,但在这里成了遍历所有的边)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值