版权声明:未经本人同意,禁止转载。 https://blog.csdn.net/qq_34022601/article/details/84642885
题目大意:
C个点,S条边,Q个询问,存在多组数据输入。
无向图边权非负,问两点间路径中边权最大值集合中,输出最大值最小的那条路径的最大值。
解题思路:
1.Floyd的变形:
如果我们把Floyd算法 变形如下:
i-->k,k-->j 的路径最大值和当前i-->j的路径最大值比较,我们选取最大值小的哪一个,Floyd仍然成立。
2.Kruskal的求解:
这道题目我们可以使用最小生成树来解决,只需要我们检查起点和终点在何时连通(并查集)。
因为最小生成树在增长的过程中基于贪心,不断把能加入路径的最短边放入生成树中,当起点终点连通时,一定保证这是一条最大边最小的路径。
代码实现:
1.Floyd的解法:
/*
Date: 01/12/18 10:01
Description:
Floyd 算法解决
*/
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int INF=1<<29;
struct Node{
vector <int> adj;
}g[105];
int dis[105][105];
void Floyd(int c)
{
for (int k=1;k<=c;k++)
{
for (int i=1;i<=c;i++)
{
for (int j=1;j<=c;j++)
{
dis[i][j]=min(dis[i][j],max(dis[i][k],dis[k][j]));
}
}
}
}
int main()
{
int s,c,q,x,y,weight,ts,te,Case=0;
scanf ("%d%d%d",&c,&s,&q);
while ((c+s+q))
{
for(int i=1;i<=c;i++)
{
g[i].adj.clear();
for (int j=1;j<=c;j++)
{
dis[i][j]=INF;
}
}
for (int i=0;i<s;i++)
{
scanf ("%d%d%d",&x,&y,&weight);
if (dis[x][y]==INF)
{
dis[y][x]=dis[x][y]=weight;
g[x].adj.push_back(y);
g[y].adj.push_back(x);
}
if (weight<dis[x][y])
dis[y][x]=dis[x][y]=weight;
}
printf ("Case #%d\n",++Case);
Floyd(c);
for (int i=0;i<q;i++)
{
scanf("%d %d",&ts,&te);
if (dis[ts][te]!=INF)
printf ("%d\n",dis[ts][te]);
else
printf ("no path\n");
}
scanf ("%d%d%d",&c,&s,&q);
if (c+s+q)
printf ("\n");
}
return 0;
}
2.Kruskal解法:
/*
Date: 01/12/18 10:01
Description:
Kruskal 算法解决
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF=1<<29;
int u[1005],v[1005],e[1005];//点数组,边数组
int p[105];//并查集 父数组
int r[1005];
int Find(int x);
void Union(int r1,int r2);
//重载函数 用于sort
bool cmp(const int i,const int j)
{
return e[i]<e[j];
}
void Kruskal(int c,int counter,int ts,int te)
{
for (int i=1;i<=c;i++)
p[i]=-1;
int ans=-1;
for (int i=0;i<counter;i++)
{
int x=u[r[i]];
int y=v[r[i]];
int w=e[r[i]];
if (Find(x)!=Find(y))
{
Union(x,y);
ans=max(w,ans);
}
if (Find(ts)==Find(te))
break;
}
if (Find(ts)!=Find(te))
printf ("no path\n");
else
printf ("%d\n",ans);
}
int main()
{
int s,c,q,x,y,weight,ts,te,Case=0,counter=0;
scanf ("%d%d%d",&c,&s,&q);
while ((c+s+q))
{
memset(u,0,sizeof(u));
memset(v,0,sizeof(v));
memset(e,0,sizeof(e));
memset(r,0,sizeof(r));
counter=0;
for (int i=0;i<s;i++)
{
scanf ("%d%d%d",&x,&y,&weight);
u[counter]=x;
v[counter]=y;
e[counter]=weight;
counter++;
}
//Kruskal 排序一次就行
for (int i=0;i<counter;i++)
r[i]=i;
sort(r,r+counter,cmp);
printf ("Case #%d\n",++Case);
for (int i=0;i<q;i++)
{
scanf("%d %d",&ts,&te);
Kruskal(c,counter,ts,te);
}
scanf ("%d%d%d",&c,&s,&q);
if (c+s+q)
printf ("\n");
}
return 0;
}
int Find(int x)
{
if (p[x]<=0)
return x;
else
return p[x]=Find(p[x]);
}
void Union(int r1,int r2)
{
r1=Find(r1);
r2=Find(r2);
if (r1==r2)
return ;
if (p[r1]<p[r2])
p[r2]=r1;
else
{
if (p[r1]==p[r2])
p[r2]--;
p[r1]=r2;
}
}