2019 ICPC 银川区域赛 H - Delivery Route

2019 ICPC 银川区域赛 H - Delivery Route

2019 ICPC 银川区域赛 H - Delivery Route_第1张图片
2019 ICPC 银川区域赛 H - Delivery Route_第2张图片
2019 ICPC 银川区域赛 H - Delivery Route_第3张图片
给一个n个点,x条双向边,y条单向边的图,同时双向边权全为正,单向边权有可能为负,且保证单向边不会出现在环中。求从点s分别到1~ n的最短距离。

打重现赛的时候想到了 tarjan强联通缩点,内部dijkstra,外部拓扑排序来解决。
但是觉得自己图论太菜了,就和队友一起去做A题的DP
事实证明,就算是赛后补题还是花了我大半天的时候才调对

不说了,是一道好题,直接上代码,讲解代码

#include
using namespace std;
#define PII pair

const int MAXN = 25e3+10;
const int inf = 2147483647;

struct node{
    int u,v,w,nx;
    bool operator < (const node &x) const 
    {
        return u == x.u ? v < x.v : u < x.u;
    }
    bool operator == (const node &x) const
    {
        return (u == x.u &&  v ==  x.v);
    }
};

struct EDGE{
    node e[150010];
    int head[MAXN],tot;
    void add(int u,int v,int w)
    {
        e[++tot].u = u;
        e[tot].v = v;
        e[tot].w = w;
        e[tot].nx = head[u];
        head[u] = tot;
    }
}edge1,edge2,tmp;
//edge1用来存原图,跑tarjan缩点
//edge2用来存缩点后的图,用来跑拓扑排序

int in[MAXN],dis[MAXN];

int low[MAXN],dfn[MAXN],s[MAXN],slen,scnt,col[MAXN],vis[MAXN],num;

vector g[MAXN],m[MAXN];

void tarjan(int u)
{
    dfn[u] = low[u] = ++num;
    s[++slen] = u;
    vis[u] = 1;
    for (int i = edge1.head[u];i;i = edge1.e[i].nx)
    {
        int v = edge1.e[i].v;
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if (vis[v]) low[u]=min(low[u],dfn[v]);
    }
    if (dfn[u] == low[u])
    {
        scnt++;
        do
        {
            m[scnt].push_back(s[slen]);//记录下每个强联通内有哪些点
            vis[s[slen]] = 0;
            col[s[slen]] = scnt;//记录每个点属于哪个强连通块
        } while (s[slen--] != u);
    }
}

void dij(int s) {
	priority_queue,greater> q;
    bool check[MAXN] = {};
	q.push(PII(dis[s],s));
	while (!q.empty())
	{
		int d = q.top().first;
		int u = q.top().second;
		q.pop();
		if (check[u] || d > dis[u]) continue;
        check[u] = 1;
		for (int i = edge1.head[u];i;i = edge1.e[i].nx)
		{
            PII y(d+edge1.e[i].w,edge1.e[i].v);
            //如果v和s不属于同一个连通块 或者 v已经访问过 就跳过
            if (col[y.second] != col[s] || check[y.second]) continue;
			if (dis[y.second]>y.first)
			{
				dis[y.second] = y.first;
				q.push(y);
			}
		}
	}
}

queue q;

void update(int last)
{
    //连通块内部的每个点都跑一遍,更新到其他连通块的起始点的距离
    for (int i = 0;i

你可能感兴趣的:(tarjan,拓扑排序,dijkstra)