【Floyd求多源最短路】模板+例题x2

Floyd多源

优点:多源时高效,好打,多源,可负权,稠密图效果更好。 

缺点:时间复杂度比较高,不适合计算大量数据。 

const int inf = 0x3f3f3f3f;
int g[MAX_N][MAX_N];  // 算法中的 G 矩阵

// 初始化 g 矩阵
void init() {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (i == j) {
                g[i][j] = 0;
            } else {
                g[i][j] = inf;
            }
        }
    }    
}

// 插入一条带权有向边
void insert(int u, int v, int w) {
    g[u][v] = w;
}

// 核心代码
void floyd() {
    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (g[i][k] + g[k][j] < g[i][j]) {
                    g[i][j] = g[i][k] + g[k][j];
                }
            }
        }
    }    
}

主要就是一个“找转接点”的思想来求最短路。需要根据题意灵活变通。


例题 蒜头年会


大致思路

把关系想象成图,员工之间亲密度要取可能亲密度之中的最小值——则要用floyd求多源最短路。

赋权值

要注意一个项目之中的每个员工之间都要建立关系(亲密度=1),且根据题意亲密度不叠加。

而且,联系实际,自己和自己不应该有什么亲密度一说,所以在最后关键步骤那里注意 i!=j !!!


代码

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int MAXN=305;
int g[MAXN][MAXN];
const int INF=0x3f3f3f3f;
void init()
{
	memset(g,0x3f,sizeof(g));
}


int main()
{
	init();
	int n,m;
	cin>>n>>m;
	while(m--)
	{
		int nn;
		scanf("%d",&nn);
		int d1[nn];
		int d2[nn];
		for(int i=0;i<nn;i++)
		{
			cin>>d1[i];
			d2[i]=d1[i];
		}
		for(int i=0;i<nn;i++)
		{
			for(int j=0;j<nn;j++)
			{
				if(i!=j)
				{
					g[d1[i]][d2[j]]=1;  //根据题意,只要在同一项目中工作过则亲密度为1,不叠加。 
				}
			}
		}
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(i!=j && g[i][k]+g[k][j]<g[i][j]) //注意i!=j
					g[i][j]=g[i][k]+g[k][j];
			}
		}
	}
	double minn=INF; 
	for(int i=1;i<=n;i++)
	{
		double sum=0;
		for(int j=1;j<=n;j++)
		{
			if(i!=j)
			{
				sum+=g[i][j];
			}
		}
		sum=sum/(n-1); //不用算自己 (细节注意)
		minn=min(sum,minn);
	}
	cout<<(int)(minn*100);
	return 0;
}


例题:美丽的邂逅


思路:

模板题。主要还是注意“自己和自己不用去找隔了几个人 i!=j”,建图,每个边权值都=1,然后根据题意,最后遍历每两个点间的最短路若>7(可画图,如果两个点之间隔了6个点,则隔了7条边,路径长度为7)则结论不成立。

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int MAXN=305;
int g[MAXN][MAXN];
const int INF=0x3f3f3f3f;
void init()
{
	memset(g,0x3f,sizeof(g));
}


int main()
{
	init();
	int n,m;
	cin>>n>>m;
	while(m--)
	{
		int a,b;
		cin>>a>>b;
		g[a][b]=1;
		g[b][a]=1;
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(i!=j && g[i][k]+g[k][j]<g[i][j])
					g[i][j]=g[i][k]+g[k][j];
			}
		}
	}
	int flag=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j)
				continue;
			if(g[i][j]>7)
			{
				flag=0;
				cout<<"No";
				return 0;
			}
		}
	}
	if(flag)	cout<<"Yes";
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值