題目傳送門: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;
}