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

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

#include 
#include 
#include 
#include 
using namespace std;
const int maxn=1e3+4;
vectorint,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;ireturn;
     }
     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;i1);
    vis[1]=true;
    d[1]=0;
    while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=0;iint to=g[u][i].first;
                int cost=g[u][i].second;
                if(d[to]if(!vis[to]){
                        q.push(to);
                        vis[to]=true;
                     }
                }
                else if(d[to]==d[u]+cost){
                     for(int x=0;xint 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;iif(!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;iscanf("%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 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn=1e3+4;
vectorint,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;i1);
    vis[1]=true;
    d[1]=0;
    while(!q.empty()){
          int u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=0;iint to=g[u][i].first;
                int cost=g[u][i].second;
                if(d[to]for(int x=0;xif(!vis[to]){
                        q.push(to);
                        vis[to]=true;
                     }
                }
                else if(d[to]==d[u]+cost){
                     for(int x=0;x//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;i1].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;iscanf("%d%d%d",&a,&b,&c);
         g[a].push_back(make_pair(b,c));
    }
    //puts("!!!");
    spfa();
    return 0;
}

你可能感兴趣的:(图论)