vijos1027-spfa&关键路径-休息中的阿呆

https://vijos.org/p/1027
给定一个有向图,n个顶点,m个边。每个边有时间作为边权,问从1到n,最少花费多少时间可以把真个图都过一遍(把每个顶点都过一遍)。并且输出所有可能经过的点(用最少时间t走的所有可能经过的点)
思路:spfa改下方向就好了,把d数组改成无穷小,关键路径的输出我是用一个vector存的。当进行松弛操作的时候,如果成功就改。
两种输出关键路径的方法。
坑点:题目中说所有可能的点,意思是如果有两条同样长的点,那么要一起输出,最好的方法是erase和unique了。
我开始以为只要进行过松弛操作,只要把进行过松驰过操作的所有点(to和u都记录,)通过去重就可以得到答案,但是其实不然,因为最长(短)路一定松驰,但是松驰不一定是最长(短)路
见下图,红色的区域发生过松弛操作,但是一定不可能在最短路中
这里写图片描述

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+4;
vector<pair<int,int> >g[maxn];
int d[maxn];
bool vis[maxn];
vector<int>kk[maxn];
int m;
int mp[maxn][maxn];
vector<int>w;
void dfs(int s,vector<int>q,int v){
     if(!s){
        for(int i=0;i<q.size();i++){
            w.push_back(q[i]);
        }
        return;
     }
     for(int i=1;i<=m;i++){
         vector<int>p(q.begin(),q.end());
         if(d[i]==(s-mp[v][i])&&mp[v][i]){
            p.push_back(i);
            dfs(d[i],p,i);
         }
     }
     return;
}
void spfa(){
    queue<int>q;
    memset(vis,false,sizeof(vis));
    memset(d,-0x3f3f3f3f,sizeof(d));
    for(int i=0;i<maxn;i++)kk[i].clear();
    q.push(1);
    vis[1]=true;
    d[1]=0;
    while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=0;i<g[u].size();i++){
                int to=g[u][i].first;
                int cost=g[u][i].second;
                if(d[to]<d[u]+cost){
                     d[to]=d[u]+cost;
                     if(!vis[to]){
                        q.push(to);
                        vis[to]=true;
                     }
                }
                else if(d[to]==d[u]+cost){
                     for(int x=0;x<kk[u].size();x++){
                        kk[to].push_back(kk[u][x]);
                     }
                     kk[to].push_back(u);
                }
            }
    }
    int s=d[m+1];
    printf("%d\n",s);
    vector<int>ss;ss.clear();
    w.clear();
    dfs(s,ss,m+1);
    w.push_back(m+1);
    sort(w.begin(),w.end());
    w.erase(unique(w.begin(),w.end()),w.end());
    for(int i=0;i<w.size();i++){
        if(!i)
            printf("%d",w[i]);
        else
            printf(" %d",w[i]);
    }
    printf("\n");
}
int main()
{   int n,a,b,c;
    scanf("%d%d",&m,&n);
    for(int i=0;i<n;i++){
         scanf("%d%d%d",&a,&b,&c);
         g[a].push_back(make_pair(b,c));
         mp[a][b]=c;
         mp[b][a]=c;
    }
    spfa();
    return 0;
}

第一个代码还是有点麻烦,得用邻接矩阵(如果存图也用邻接矩阵就没那么麻烦了)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+4;
vector<pair<int,int> >g[maxn];
int d[maxn];
bool vis[maxn];
vector<int>kk[maxn];
int m;
void spfa(){
    queue<int>q;
    memset(vis,false,sizeof(vis));
    memset(d,-0x3f3f3f3f,sizeof(d));
    for(int i=0;i<maxn;i++)kk[i].clear();
    q.push(1);
    vis[1]=true;
    d[1]=0;
    while(!q.empty()){
          int u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=0;i<g[u].size();i++){
                int to=g[u][i].first;
                int cost=g[u][i].second;
                if(d[to]<d[u]+cost){
                     d[to]=d[u]+cost;
                     kk[to].clear();
                     for(int x=0;x<kk[u].size();x++){
                        kk[to].push_back(kk[u][x]);
                     }
                     kk[to].push_back(u);
                     if(!vis[to]){
                        q.push(to);
                        vis[to]=true;
                     }
                }
                else if(d[to]==d[u]+cost){
                     for(int x=0;x<kk[u].size();x++){
                        kk[to].push_back(kk[u][x]);
                     }
                     kk[to].push_back(u);
                }
            }
    }
      //for(int i=1;i<=m+1;i++)
          //printf("**%d\n",d[i]);
    sort(kk[m+1].begin(),kk[m+1].end());
    kk[m+1].erase(unique(kk[m+1].begin(),kk[m+1].end()),kk[m+1].end());
    printf("%d\n",d[m+1]);
    for(int i=0;i<kk[m+1].size();i++){
        if(!i)
              printf("%d",kk[m+1][0]);
        else
              printf(" %d",kk[m+1][i]);
    }
    printf(" %d",m+1);
    printf("\n");
}
int main()
{   int n,a,b,c;
    scanf("%d%d",&m,&n);
    for(int i=0;i<n;i++){
         scanf("%d%d%d",&a,&b,&c);
         g[a].push_back(make_pair(b,c));
    }
    //puts("!!!");
    spfa();
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35781950/article/details/79952182
个人分类: 图论
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭