HDU - 6166 SPFA最短路次短路 or 二進制+Dijstra

題目傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=6166

題意:給一個有向圖,給一個集合,從集合內任選兩個點的最短路最短爲多少。

分析:兩種解法,一種是題解中給的,感覺非常巧妙,把集合分爲兩個集合,改成多源多匯最短路,如何保證任意一對點都分在過不同的集合呢,就是使用二進制,對於每一二進制位,二進制表示下不同的就分在不同的集合,因爲對於每一對數,至少有一位二進制不同,所有保證每一對點都被分在過不同的集合了。第二種解法就比較笨,比賽中沒有想到題解那麼好的解法,就直接使用了SPFA進行鬆弛操作,但是要防止自己走向自己的情況,就保存了最終父節點不同的最短路和次短路,然後一直鬆弛到不能鬆弛爲止就行了。

代碼:

第一種解法的代碼網上很多,也很好寫,遍歷二進制位,然後對於每一位,使用Dijstra,爲0的dis設爲0,爲1的做個標記,跑的過程中,走到任意一個有標記的就可以return了,寫起來很簡單,代碼就不給出了。

第二種代碼:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f

using namespace std;

const int maxm=200005;
const int maxn=100005;

int m,n;
int edgenum,head[maxn],num[maxn];
long long dis[2][maxn];
int vis[maxn];
int fa[2][maxn];

deque<int> que;

struct node
{
	int to,len,next;
}edge[maxm];

void init(int n)
{
    que.clear();
	edgenum=0;
	for(int i=1;i<=n;i++)
    {
        head[i]=-1;
        dis[0][i]=dis[1][i]=inf;
        fa[0][i]=fa[1][i]=0;
        vis[i]=0;
    }
}

int add(int u,int v,int d)
{
	edge[edgenum]={v,d,head[u]};
	head[u]=edgenum++;
}

int main()
{
    //freopen("1006.in","r",stdin);
    ios::sync_with_stdio(false);
    int T,n,m,u,v,len,k,a[100005];
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        cin>>n>>m;
        init(n);
        for(int i=1;i<=m;i++)
        {
            cin>>u>>v>>len;
            add(u,v,len);
        }
        cin>>k;
        for(int i=1;i<=k;i++)
        {
            cin>>a[i];
            for(int j=head[a[i]];j!=-1;j=edge[j].next)
            {
                int v=edge[j].to;
                if(dis[0][v]>edge[j].len)
                {
                    if(a[i]==fa[1][v])
                    {
                        fa[1][v]=fa[0][v];
                        dis[1][v]=dis[0][v];
                    }
                    if(!vis[v])
                    {
                        vis[v]=1;
                        que.push_back(v);
                    }
                    fa[0][v]=a[i];
                    dis[0][v]=edge[j].len;
                }
                else if(dis[1][v]>edge[j].len&&a[i]!=fa[0][v])
                {
                    if(!vis[v])
                    {
                        vis[v]=1;
                        que.push_back(v);
                    }
                    fa[1][v]=a[i];
                    dis[1][v]=edge[j].len;
                }
            }
        }
        while(!que.empty())
        {
            int u=que.front();
            que.pop_front();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                for(int j=0;j<=1;j++)
                {
                    if(v!=fa[j][u])
                    {
                        if(dis[0][v]>dis[j][u]+edge[i].len)
                        {
                            if(fa[j][u]==fa[1][v])
                            {
                                fa[1][v]=fa[0][v];
                                dis[1][v]=dis[0][v];
                            }
                            if(!vis[v])
                            {
                                vis[v]=1;
                                que.push_back(v);
                            }
                            fa[0][v]=fa[j][u];
                            dis[0][v]=dis[j][u]+edge[i].len;
                        }
                        else if(dis[1][v]>dis[j][u]+edge[i].len&&fa[j][u]!=fa[0][v])
                        {
                            if(!vis[v])
                            {
                                vis[v]=1;
                                que.push_back(v);
                            }
                            fa[1][v]=fa[j][u];
                            dis[1][v]=dis[j][u]+edge[i].len;
                        }
                    }
                }
            }
        }
        long long ans=inf;
        for(int i=1;i<=k;i++)
            ans=min(ans,dis[0][a[i]]);
        cout<<"Case #"<<ca<<": "<<ans<<endl;
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章