您的位置:首页 > Web前端 > JavaScript

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

2017-08-23 15:52 423 查看
题目传送门: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: