算法提高课第三章Floyd算法及拓展应用

floyd算法可以解决的问题:

  • 最短路
  • 传递闭包
  • 找最小环
  • 恰好经过k条边的最短路(倍增)
    在这里插入图片描述
//初始化
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
if(i != j) dist[i][j] = inf; 

集合:所有从i出发,最终走到j,且中间只经过节点编号不超过k的所有路径
属性:路径长度的最小值

最短路

AcWing 1125. 牛的旅行

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define x first
#define y second
using namespace std;
//floyd求任意两点的最短距离
//求maxd[i], 和i联通且距离最远的点
//情况1:所有maxd[i]的最大值
//情况2:枚举哪两个点连边。i,j满足d[i, j] = inf, maxd[i] + dist[i, j] + maxd[j]
const int N = 160;
int n;
const double inf = 1e20;
double d[N][N], maxd[N];
typedef pair<int, int> PII;
char g[N][N];
PII q[N];
double get_dist(PII a, PII b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
int main()
{
   cin >> n;
   for(int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
   
   for(int i = 0; i < n; i ++ ) cin >> g[i];
   

   for(int i = 0; i < n; i ++ )
   for(int j = 0; j < n; j ++ )
   {
       if(i != j)
       if(g[i][j] == '1') d[i][j] = get_dist(q[i], q[j]);
       else d[i][j] = inf;
   }
   
   for(int k = 0; k < n; k ++ )
   for(int i = 0; i < n; i ++ )
   for(int j = 0; j < n; j ++ )
       d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

   
   for(int i = 0; i < n; i ++ )
   for(int j = 0; j < n; j ++ )
       if(d[i][j] < inf)
            maxd[i] = max(maxd[i], d[i][j]);
            
   double res1 = 0;
   for(int i = 0; i < n; i ++ ) res1 = max(res1, maxd[i]);//最大半径
   
   double res2 = inf;
   for(int i = 0; i < n; i ++ )
   for(int j = 0; j < n; j ++ )
       if(d[i][j] >= inf)
           res2 = min(res2, get_dist(q[i], q[j]) + maxd[i] + maxd[j]);
           
   printf("%.6f", max(res1, res2));
}

传递闭包

两个点可以间接连接,则可以直接相连。
初始化,做一遍Floyd
如果i能到kk能到j则i能到j

#include<bits/stdc++.h>
#define intn long long
using namespace std;
queue<pair<int ,int> >q;
vector<int >g[50];
int ind[50];
int indz[50];
int main()
{
	int n,m;
	char a,t,b;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>a>>t>>b;
		q.push(make_pair(a-'A'+1,b-'A'+1));//存储m组排序序 
	}
	for(int k=1;k<=m;k++)//枚举排序 
	{
		int ind0_num=0;
		int flag=1;
		pair<int,int> now=q.front();q.pop();
		g[now.first].push_back(now.second);//存边 
		indz[now.second]++;//每次 进行更新入度 
		queue<int>qq;
		for(int i=1;i<=n;i++)
		{
			ind[i]=indz[i];//使用更新后的入度 
			if(ind[i]==0)
			{
				qq.push(i);// 将入度为零的点入队 
			
				ind0_num++;//找到入度为零的点的个数,如果多于1,说明有些关系没有确定 
			}
		}
		if(ind0_num!=1)
		{
		 	flag=0;
		}
		int cnt=0;
		int ans[30];
		while(!qq.empty())//拓扑排序 
		{
			int a=qq.front();
			qq.pop();
			ans[++cnt]=a;//存储答案 		
			ind0_num=0;		
			for(int i=0;i<g[a].size();i++)
			{
				ind[g[a][i]]--;//更新入度 
				if(ind[g[a][i]]==0)
				{
					qq.push(g[a][i]);//入队 
					ind0_num++;		
				}
			}
			if(ind0_num>1)
			{
				flag=0;
			}
		}
		if(cnt!=n)//如果cnt!=n,说明有环 
		{
			printf("Inconsistency found after %d relations.",k);
			return 0;
		}
		else
		{
			if(flag==0)//如果flag=0,说明有点的排序未确定 
			{
				continue;
			}
			else
			{
				printf("Sorted sequence determined after %d relations: ",k);
				for(int i=1;i<=n;i++)
				{
					printf("%c",ans[i]+'A'-1);
				}
				printf(".");
				return 0;
			}
		}
	}
	printf("Sorted sequence cannot be determined.");
}


拓扑排序

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
int cnt, n, m, type, d[26], f[26];
bool st[26]; //记录当前节点是否出现过

void topsort(int i, vector<int> graph[]) {
    queue<int> q;
    memcpy(d, f, sizeof f);
    //初始时将所有入度为0的节点入队
    for (int i = 0; i < n; ++i) {
        if (d[i] == 0) q.push(i);
    }
    string ans;
    bool unique = true;
    while (!q.empty()) {
        //特判不能同时有两个入度为0的点存在,例如A->B , C->D,这两个序列显然不能推出关系
        if (q.size() > 1) {   
            unique = false;//一定是最小的入栈,排序是一条链
        }
        int cur = q.front();
        char ch = 'A' + cur;
        ans += ch;
        q.pop();
        for (int ne : graph[cur]) {
            if (--d[ne] == 0) q.push(ne);
        }
    }
    //如果序列合法的话拓扑排序可以将所有节点的入度变为0,反之就是不合法
    if (ans.size() < cnt) {  
        type = 2;//有环
        printf("Inconsistency found after %d relations.\n", i);
    }

    //合法的条件就是
    if(ans.size() == n && unique) {
        type = 1;
        printf("Sorted sequence determined after %d relations: %s.\n", i, ans.c_str());
    }
}


int main() {
    string s;
    while (cin >> n >> m, n || m) {
        memset(f, 0, sizeof f);
        memset(st, 0, sizeof st);
        type = 0;
        cnt = 0;   //记录当前出现的元素个数
        vector<int> graph[26];

        for (int i = 1; i <= m; ++i) {
            cin >> s;
            if (type) continue;
            int a = s[0] - 'A', b = s[2] - 'A';
            if (!st[a]) {
                st[a] = true;//多一个变量
                ++cnt;
            }
            if (!st[b]) {
                st[b] = true;//多一个变量
                ++cnt;
            }
            graph[a].push_back(b);
            f[b]++;
            topsort(i, graph);
        }
        if (!type) printf("Sorted sequence cannot be determined.\n");
    }
    return 0;
}

最小环


k是不算ij中间点的最大值,满足三角不等式

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;

int n, m;
int d[N][N], g[N][N];
int pos[N][N];
int path[N], cnt;
const int INF = 0x3f3f3f3f;
void get_path(int i, int j)
{
    if(pos[i][j] == 0) return;
    int k = pos[i][j];
    get_path(i, k);
    path[cnt ++] = k;
    get_path(k, j);
}
int main()
{
    cin >> n >> m;
    memset(g, 0x3f, sizeof g);
    for(int i = 1; i <= n; i ++ )g[i][i] = 0;
    
    while(m --)
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b], c);
    }
    int res = INF;
    memcpy(d, g, sizeof d);
    for(int k = 1; k <= n; k ++ )
    {
        for(int i = 1; i < k; i ++ )
        for(int j = i + 1; j < k; j ++ )
            if((long long)d[i][j] + g[j][k] + g[i][k] < res)
            {
                res = d[i][j] + g[j][k] + g[i][k];
                cnt = 0;
                path[cnt ++] = k;
                path[cnt ++] = i;
                get_path(i, j);
                path[cnt ++] = j;
            };
            
        
        
        for(int i = 1; i <= n; i ++ )
        {
            for(int j = 1; j <= n; j ++ )
            {
                if(d[i][j] > d[i][k] + d[k][j])
                {
                    d[i][j] = d[i][k] + d[k][j];
                    pos[i][j] = k;
                }
            }
        }
    }
    if(res == INF) puts("No solution.");
    else 
    {
        for(int i = 0; i < cnt; i ++ )cout << path[i] << " ";
        cout << endl;
    }
}

类Floyd

AcWing 345. 牛站

题解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值