ACM学习历程—HDU5521 Meeting(图论)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5521

学习菊苣的博客,只粘链接,不粘题目描述了。

题目大意就是一个人从1开始走,一个人从n开始走。让最后相遇的时间最短。

题目就是个最短路,不过唯一不同的是,题目图的描述方式比较特别。

从规模上来看,想把这张图描述成邻接矩阵或者邻接表是不可能的。

必然只能按照题目要求的意思来存。

于是第一步存图的方式,我采用了两个vector数组,(当然此处可以使用链式前向星),一个存了和点相关的集合有哪些in[],即这个点包含在哪些集合里面;一个存了集合里面有哪些点edge[]

然后就是跑两遍最短路了,这里我采用了优先队列的spfa(貌似就是优先队列的dijikstra)。

不过直接这样上去T了好多发。

然后考虑到用了优先队列后,相当于优化了这个dp的过程,让每个点只需要遍历一次。那么,自然而然的,如果i遍历了集合s里面的所有点,自然集合s也只需要遍历一次。加了这一个剪枝就能AC了。由于遍历集合的时候,不是按照从最小权值集合开始的,所以这里没有对队列里面的元素进行判重,不过影响不是很大。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#define LL long long

using namespace std;

struct node
{
    int id, val;
    bool operator<(const node x) const
    {
        return val>x.val;
    }
};
const int maxN = 100005;
const int maxM = 1000005;
int n, m;
vector<int> in[maxN];
int dis[maxM];
vector<int> edge[maxM];
LL p[2][maxN];
bool vis[maxM];

void input()
{
    scanf("%d%d", &n, &m);
    int t, s, k;
    for (int i = 0; i < m; ++i)
    {
        scanf("%d%d", &t, &s);
        dis[i] = t;
        for (int j = 0; j < s; ++j)
        {
            scanf("%d", &k);
            in[k].push_back(i);
            edge[i].push_back(k);
        }
    }
    memset(p, -1, sizeof(p));
}

void spfa(int from, int x)
{
    memset(vis, false, sizeof(vis));
    priority_queue<node> q;
    node k, t;
    int w, u, v;
    k.id = from;
    k.val = 0;
    q.push(k);
    p[x][from] = 0;
    while (!q.empty())
    {
        k = q.top();
        q.pop();
        u = k.id;
        for (int i = 0; i < in[u].size(); ++i)
        {
            w = in[u][i];
            if (vis[w]) continue;
            for (int j = 0; j < edge[w].size(); ++j)
            {
                v = edge[w][j];
                if (u == v) continue;
                if (p[x][v] == -1 || p[x][v] > p[x][u]+dis[w])
                {
                    p[x][v] = p[x][u]+dis[w];
                    t.id = v;
                    t.val = p[x][v];
                    q.push(t);
                }
            }
            vis[w] = true;
        }
    }
}

LL myMin(LL x, LL y)
{
    if (x == -1) return y;
    else return min(x, y);
}

void work()
{
    spfa(1, 0);
    spfa(n, 1);
    LL mi = -1;
    for (int i = 1; i <= n; ++i)
        if (p[0][i] != -1 && p[1][i] != -1)
            mi = myMin(mi, max(p[0][i], p[1][i]));
    if (mi == -1)
    {
        printf("Evil John\n");
        return;
    }
    printf("%d\n", mi);
    bool flag = false;
    for (int i = 1; i <= n; ++i)
        if (p[0][i] != -1 && p[1][i] != -1 && mi == max(p[0][i], p[1][i]))
        {
            if (flag) printf(" ");
            printf("%d", i);
            flag = true;
        }
    printf("\n");
}

void clss()
{
    for (int i = 0; i < m; ++i)
        edge[i].clear();
    for (int i = 1; i <= n; ++i)
        in[i].clear();
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 0; times < T; ++times)
    {
        printf("Case #%d: ", times+1);
        input();
        work();
        clss();
    }
    return 0;
}
View Code

 

posted on 2015-11-07 20:31  AndyQsmart  阅读(212)  评论(0编辑  收藏  举报

导航