1. 程式人生 > >圖論最短路——spfa

圖論最短路——spfa

print 操作 標記 pen play hide man mage 隊列

今天開始圖論的最短路的最後復習,今天自己手打spfa雖然看了一眼書,但是也算是自己打出來的,畢竟很久沒打了,而且還是一遍a代碼下來15min左右就搞完了,成就感++。所以呢來篇博客記錄一下。

技術分享圖片

香甜的黃油,當年做的時候吃了不少苦頭現在完全會打了,下面是當時我的代碼:

技術分享圖片
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<ctime>
#include
<iostream> #include<string> using namespace std; const int maxn=1002,inf=1000000000; int n,p,c,a,b,d,t,dist[maxn],s1[maxn],inq[maxn]; vector<int>g[maxn],w[maxn]; void spfa(int s) { queue<int>a;//一個隊列a for(int i=1;i<=p;i++)//循環4個牧場都附極大值 dist[i]=inf; memset(inq,0,sizeof
(inq));//清空inp dist[s]=0;//把到當前的牧場距離設為0,畢竟是自己到自己 a.push(s);//進隊 inq[s]=1;//使其為1 while(!a.empty())//如果隊列不為空 { int i=a.front();//返回隊首元素 a.pop();//彈出隊首 inq[i]=0;//使其為0 for(int k=0;k<g[i].size();k++)//當前的牧場和其余的牧場相連 { int j=g[i][k];//取i到j的牧場號詢問其距離 if
(dist[i]+w[i][k]<dist[j])//如果當前距離和i到k的距離小於j松弛操作 { dist[j]=dist[i]+w[i][k];//松弛 if(inq[j]!=0) continue;//詢問是否在隊列之中 inq[j]=1;//不在的話再次標記 a.push(j);//使當前的點進隊好像bfs但不是bfs多次進隊 } } } } int main() { //freopen("1.in","r",stdin); scanf("%d%d%d",&n,&p,&c);//n為奶牛所在的牧場號,p為4個牧場,c為5個牧場的關系 memset(s1,0,sizeof(s1));//s1存的是奶牛的牧場位置; for(int i=1;i<=n;i++) { scanf("%d",&t);// s1[t]++;//牧場 } for(int i=1;i<=c;i++) { scanf("%d%d%d",&a,&b,&d);//a與b之間的距離為d g[a].push_back(b);//擴邊 g[b].push_back(a); w[a].push_back(d);//二次擴邊 w[b].push_back(d); } int ans=inf;//附最大值 for(int i=1;i<=p;i++)//枚舉每一個牧場為起點 { spfa(i);//當黃油放在第i個牧場時來一個一個判斷;跑距離 int sum=0; for(int j=1;j<=p;j++) { if(!s1[j]) continue; sum+=dist[j]*s1[j]; //計算奶牛到牧場的距離和 } ans=min(sum,ans); //取最小值 } printf("%d",ans); return 0; }
View Code

註釋很多很多,主要因為當時的不理解。

下面是本人今天的代碼!!!

技術分享圖片
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<map>
#define inf 10000000
using namespace std;
const int maxn=5000;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
int b[maxn],ver[maxn],lin[maxn],nex[maxn],len=0,e[maxn],minn=inf,dis[maxn],q[maxn];
bool vis[maxn];
void add(int x,int y,int z)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
    e[len]=z;
}
int n,m,k,h,t;
void spfa(int x)
{
    memset(vis,0,sizeof(vis));
    memset(dis,10,sizeof(dis));
    memset(q,0,sizeof(q));
    dis[x]=0;vis[x]=1;q[1]=x;
    h=0,t=1;
    while(h<=t)
    {
        int tn=q[++h];vis[tn]=0;
        for(int i=lin[tn];i;i=nex[i])
        {
            int tmp=ver[i];
            if(dis[tn]+e[i]<dis[tmp])
            {
                dis[tmp]=dis[tn]+e[i];
                if(vis[tmp]!=1)
                {
                    q[++t]=tmp;
                    vis[tmp]=1;
                }
            }
        }
    }
}
int main()
{
    freopen("1.in","r",stdin);
    k=read();m=read();n=read();
    memset(b,0,sizeof(b));
    for(int i=1;i<=k;i++){int x;x=read();b[x]++;}
    for(int i=1;i<=n;i++)
    {
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);
        add(y,x,z);
    }
    for(int i=1;i<=m;i++)
    {
        int ans=0;
        spfa(i);
        for(int j=1;j<=m;j++)
        {
            if(b[j]!=0)
                ans+=dis[j]*b[j];
        }
        minn=min(ans,minn);
    }
    printf("%d\n",minn);
    return 0;
}
View Code

思路很清晰的打完了哈哈。

莫聽穿林打葉聲,何妨吟嘯且徐行。

圖論最短路——spfa