暑假 D4T1 path(反向建图 dijkstra)

Description

众所周知,Bfk 经常为找不到路而烦恼

Bfk 终于迎来了它高中以来第一个完整的暑假,它决定从假期里抽出一段时间去日本

旅游。可是,对于连教师宿舍都找不到的 Bfk 来说,在旅途中不迷路是一件很困难的事

情。为了避免迷路的尴尬,Bfk 早早的就规划起了它的行程。它将日本的地图抽象成了一

张 n 个点 m 条边的有向图,并在上面选定了行程的起点和终点,但它在规划旅行路径时却

犯了难。它希望路径上的点都满足该点的出边所指向的点都能直接或间接的到达终点,这

样即使它走错了路,也能重新规划路线到达终点。另外,它还希望旅行的路程尽可能短,

以便节约更多的时间预习大学课程。

现在,Bfk 找到了你,希望你能帮帮它。它不想为难你,因此你不用输出具体的方

案,只需要告诉它满足条件的路径的最短长度就可以了

Input

第一行两个整数 ?? 和 ?? ,含义如题

接下来 m 行,每行三个整数 ??, ??, ?? ,描述一条从 ?? 指向 ?? 的单向边,长度为??

接下来一行两个整数 ??,??,表示起点和终点

Output

输出一行一个数字,表示满足要求的路径的最短长度

特别的,如果不存在这样的路径,则输出“-1”(不含引号)

题解

由于做过最优贸易,所以对于点到达终点的条件可以很容易转换,建立反图,从t跑。

考虑所有路径上的点满足出边的点都能到终点的条件,可以在dfs时记录到达该节点的次数,

该次数等同于这个点出边的点可以到t的个数。

最后再用满足条件的点建出正向的图,跑最短路即可。

于是愉快的spfa和只是大的大数据。

#include<bits/stdc++.h>
using namespace std;

const int maxn=100005;
int n,m,s,t;
vector<pair<int,int> >e[maxn],a[maxn];
int chu[maxn],cnt[maxn];

template<class T>inline void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

void dfs(int u){
    //printf("%d ",u);
    for(unsigned int i=0;i<a[u].size();i++){
        int v=a[u][i].first;
        cnt[v]++;
        if(cnt[v]==1)
         dfs(v);
    }
}

queue<int> q;
bool vis[maxn];
int dis[maxn];

void spfa(){
    for(int i=1;i<=n;i++) dis[i]=0x7ffffff;
    q.push(s);
    vis[s]=true;dis[s]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        vis[x]=false;
        for(unsigned int i=0;i<e[x].size();i++){
            int y=e[x][i].first;
            if(dis[y]>dis[x]+e[x][i].second){
                dis[y]=dis[x]+e[x][i].second;
                if(!vis[y]) {vis[y]=true;q.push(y);}
            }
        }
    }
}

int main(){
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=m;i++){
        int x,y,z;
        read(x);read(y);read(z);
        if(x==y) continue;
        chu[x]++;
        a[y].push_back(make_pair(x,z));
    }
    read(s);read(t);
    cnt[t]=1;
    dfs(t);
    //for(int i=1;i<=n;i++) printf("%d %d\n",cnt[i],chu[i]);
    if(!cnt[s]) {printf("-1");return 0;}
    cnt[t]=chu[t];
    for(int i=1;i<=n;i++)
     if(cnt[i]==chu[i]){
         for(unsigned int j=0;j<a[i].size();j++){
             int x=a[i][j].first,y=a[i][j].second;
             if(chu[x]==cnt[x]){
                 e[x].push_back(make_pair(i,y));
                 //printf("%d %d %d\n",i,x,y);
        }

         }
    }
    spfa();
    if(dis[t]==0x7ffffff) printf("-1");
    else printf("%d",dis[t]);
}
/*6 7
2 1
3 1
4 1
4 1
5 1
4 1
6 1
4
*/

关于spfa,他死了

都9102年了,还有人卡spfa

只有用堆优化的dijkstra

#include<bits/stdc++.h>
using namespace std;

const int maxn=1000005;
#define ll long long
int n,m,s,t;
vector<pair<int,ll> >e[maxn],a[maxn];
int chu[maxn],cnt[maxn];

template<class T>inline void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

void dfs(int u){
    //printf("%d ",u);
    for(unsigned int i=0;i<a[u].size();i++){
        int v=a[u][i].first;
        cnt[v]++;
        if(cnt[v]==1)
         dfs(v);
    }
}

priority_queue < pair < ll,int >,vector < pair < ll,int > >,greater < pair < ll ,int > > > q;
bool vis[maxn];
ll dis[maxn];

void dijkstra(){
    for(int i=1;i<=n;i++) dis[i]=0x7fffffff;
    dis[s]=0;
    q.push(make_pair(dis[s],s));
    while(!q.empty()){
        int x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=true;
        for(unsigned int i=0;i<e[x].size();i++){
            int y=e[x][i].first;
            if(vis[y]) continue;
            if(dis[y]>dis[x]+e[x][i].second){
                dis[y]=dis[x]+e[x][i].second;
                q.push(make_pair(dis[y],y));
            }
        }
    }
}

int main(){
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=m;i++){
        int x,y;
        ll z;
        read(x);read(y);read(z);
        if(x==y) continue;
        chu[x]++;
        a[y].push_back(make_pair(x,z));
    }
    read(s);read(t);
    cnt[t]=1;
    dfs(t);
    //for(int i=1;i<=n;i++) printf("%d %d\n",cnt[i],chu[i]);
    if(!cnt[s]) {printf("-1");return 0;}
    cnt[t]=chu[t];
    for(int i=1;i<=n;i++)
     if(cnt[i]==chu[i]){
         for(unsigned int j=0;j<a[i].size();j++){
             int x=a[i][j].first,y=a[i][j].second;
             if(chu[x]==cnt[x]){
                 e[x].push_back(make_pair(i,y));
                 //printf("%d %d %d\n",i,x,y);
        }

         }
    }
    dijkstra();
    if(dis[t]==0x7fffffff) printf("-1");
    else printf("%lld",dis[t]);
}
/*6 7
1 2 1
1 3 1
3 4 1
2 4 1
3 5 1
5 4 1
5 6 1
1 4
*/

原文地址:https://www.cnblogs.com/sto324/p/11181659.html

时间: 2024-10-09 19:50:58

暑假 D4T1 path(反向建图 dijkstra)的相关文章

poj1122 FDNY to the Rescue!(dij+反向建图+输出路径)

题目链接:poj1122 FDNY to the Rescue! 题意:给出矩阵,矩阵中每个元素tij表示从第i个交叉路口到第j个交叉路口所需时间,若tij为-1则表示两交叉路口之间没有直接路径,再给出火警位置所在的交叉路口 和 一个或多个消防站所处的交叉路口位置.输出要求按消防站到火警位置所需时间从小到大排列,输出信息包括消防站位置(初始位置),火警位置(目标位置),所需时间,最短路径上每个交叉路口. 题解:反向建图,从火警位置求一次最短路,求最短路时记录路径,按时间从小到大输出. 1 #in

hdu3499(分层图最短路 or 反向建图)

传送门 方法一:分层图 #include<bits/stdc++.h> #define per(i,a,b) for(int i=a;i<=b;i++) #define mod 1000000007 using namespace std; typedef long long ll; const ll inf =23333333333333333LL; const double eps=1e-8; int T; int read(){ char ch=getchar(); int res

VJ - H - Almost the shortest route - 图论(反向建图)

https://vjudge.net/contest/351913#problem/H N cities (2 ≤ N ≤ 10 000 ) are connected by a network of M one-way roads (1 ≤ M < 100 000 000 ). It is known that these roads do not cross outside the cities. The numeration of the cities and the roads star

HDU2647(拓扑排序+反向建图)

题意不说了,说下思路. 给出的关系是a要求的工资要比b的工资多,由于尽可能的让老板少付钱,那么a的工资就是b的工资+1,可以确定关系为a>b,根据拓扑排序建边的原则是把"小于"关系看成有向边,那么我们可以建边v->u. #include <stdio.h> #include <string.h> #include <string> #include <iostream> #include <algorithm> #

ZOJ2750Idiomatic Phrases Game 建图Dijkstra

Dijkstra部分不难,主要是建图 #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<iostream> using namespace std; #define INF 10000000 #define maxn 1005 struct bian { string a; string

HDU1535Invitation Cards(有向图,正向建图和反向建图各spfa一次)

Invitation Cards Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2374    Accepted Submission(s): 1151 Problem Description In the age of television, not many people attend theater performances.

POJ 3687 反向建图+拓扑

Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11146   Accepted: 3192 Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N in such a way that: No two balls share

HDU4857——逃生(反向建图+拓扑排序)

逃生 Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前.同时,社会是不平等的,这些人有的穷有的富.1号最富,2号第二富,以此类推.有钱人就贿赂负责人,所以他们有一些好处.负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推.那么你就要安排大家的顺序.我们保证一

HDU 3639 Hawk-and-Chicken(强连通缩点+反向建图)

http://acm.hdu.edu.cn/showproblem.php?pid=3639 题意: 有一群孩子正在玩老鹰抓小鸡,由于想当老鹰的人不少,孩子们通过投票的方式产生,但是投票有这么一条规则:投票具有传递性,A支持B,B支持C,那么C获得2票(A.B共两票),输出最多能获得的票数是多少张和获得最多票数的人是谁? 思路: 先强连通缩点反向建图,在计算强连通的时候,需要保存每个连通分支的结点个数. 为什么要反向建图呢?因为要寻找票数最多的,那么肯定是入度为0的点,然后dfs计算它的子节点的