程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> SPFA_YZOI 1662: Easy sssp,spfa_yzoisssp

SPFA_YZOI 1662: Easy sssp,spfa_yzoisssp

編輯:C++入門知識

SPFA_YZOI 1662: Easy sssp,spfa_yzoisssp


題目描述

輸入數據給出一個有N(2  < =  N  < =  1,000)個節點,M(M  < =  100,000)條邊的帶權有向圖.  要求你寫一個程序,  判斷這個有向圖中是否存在負權回路.  如果從一個點沿著某條路徑出發,  又回到了自己,  而且所經過的邊上的權和小於0,  就說這條路是一個負權回路. 如果存在負權回路,  只輸出一行-1; 如果不存在負權回路,  再求出一個點S(1  < =  S  < =  N)到每個點的最短路的長度.  約定:    S到S的距離為0,  如果S與這個點不連通,  則輸出NoPath.

輸入

第一行:  點數N(2  < =  N  < =  1,000),  邊數M(M  < =  100,000),  源點S(1  < =  S  < =  N); 以下M行,  每行三個整數a,  b,  c表示點a,  b(1  < =  a,  b  < =  N)之間連有一條邊,  權值為c(-1,000,000  < =  c  < =  1,000,000)

輸出

如果存在負權環,  只輸出一行-1,  否則按以下格式輸出 共N行,  第i行描述S點到點i的最短路:  如果S與i不連通,  輸出NoPath; 如果i  =  S,  輸出0; 其他情況輸出S到i的最短路的長度.

    這個題真是異常的坑  打著題目是sssp的表面而實地裡卻隱藏這一刻spfa的心(貌似不通)   下面講一下spfa的詳細操作步驟(和dijkstra應該很像):

  1. g[i][j]表示鄰接矩陣  dist[i]表示源點到i的距離  cnt[i]表示點i的入隊次數  v[i]表示i這個點是否在隊列中  

  2. 初始化:v[]數組賦值為false  cnt[]=0 把所有點與源點的距離變為很大

  3. 接著 把源點入隊 再把dist[start]變為0

  4. 然後做和bfs差不多的操作  拓展隊首的點  更新新的最短的距離......

  5. 如果某個點的入隊次數>n那麼一定有負環 證明:如果一個點存在正的最短路 那麼他最多可以和其他所有點連而拓展n次  而如果是負環  那麼他的這個最短路中如果有負環  那麼就會越拓展越小  當然入隊就會超過n次

    這裡還有一個地方要注意 就是判負環 因為這個負環不一定在源點的路上 那麼是不是應該把所有點都找過去呢 顯然不是  這裡有兩個方法 推薦第二種做法:

  1. 用dfs找連通塊 然後對每一個聯通塊做SPFA

  2. 受zbt大神的指點  可以加一個入度為0  只有出邊並連著除他外所有點   那麼只要對這個點進行拓展就可以找到所有的負環

    最後還有一點就是我這樣做在vijos裡只有50分  粗部估計是這個鄰接矩陣的問題  最好改成邊集數組來做  代碼下次給

代碼如下:

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=1000+10;
long long g[maxn][maxn],dist[maxn],cnt[maxn];
bool v[maxn],used[maxn];
int n,m,s;
int a,b,c;
queue<int>q;
bool SPFA(int start)
{
    for(int i=1;i<=n;i++)
    {
        dist[i]=0x7f7f7f;
        cnt[i]=0;
        v[i]=false;
    }
    while(!q.empty())
        q.pop();
    v[start]=true;
    q.push(start);
    dist[start]=0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        v[x]=false;
        for(int k=1;k<=n;k++)
            if(g[x][k]<0x7f7f7f&&dist[x]+g[x][k]<dist[k])
            {
                dist[k]=dist[x]+g[x][k];
//              used[k]=true;
                if(!v[k])
                {
                    cnt[k]++;
                    if(cnt[k]>n)
                        return false;
                    v[k]=true;
                    q.push(k);
                }
            }
    }
    return true;
}
int main()
{
    ios::sync_with_stdio(false);
//  freopen("1.in","r",stdin);
    cin>>n>>m>>s;
    for(int i=1;i<=n+1;i++)
        for(int j=1;j<=n+1;j++)
            g[i][j]=0x7f7f7f;
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b>>c;
        if(c<g[a][b])
            g[a][b]=c;
    }
    for(int i=1;i<=n;i++)
        g[n+1][i]=1;
//  for(int i=1;i<=n;i++)
//  {
//      for(int j=1;j<=n;j++)
//          cout<<g[i][j]<<' ';
//      cout<<endl;
//  }
//  for(int i=1;i<=n;i++)
//  {
//      if(!SPFA(i))
//      {
//          cout<<-1<<endl;
//          return 0;
//      }
//  }
    if(!SPFA(n+1))
    {
        cout<<-1<<endl;
        return false;
    }
         
    SPFA(s);
    for(int i=1;i<=n;i++)
    {
        if(dist[i]==0x7f7f7f)
        {
            cout<<"NoPath"<<endl;
            continue;
        }
        cout<<dist[i]<<endl;
    }
    return 0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved