Floyd算法

24 篇文章 0 订阅

例题2:POJ 2570某条道路由一些公司修建,修建道路的公司可以提供这条路上的连通,如第一个测试数据中,从1到2有a,b,c三个公司可以提供路径,现给你任意的两个地点,问有哪些公司可以提供路径

这个题的难点就是给你的字符串如何存储,我们用map[u][v]表示u到v可以由哪些公司提供路径。初始化为0,那么它的二进制的每一位都为0,用0~26的位置表示a~z是否可以提供路径,可以则设为1。如图输入的字符串为abc,那么可以存储最后三位都为1,其余位不存在的设为0,这个时候map[i][j]转化为10进制就为7。

问题就是怎样把最后的三位改为1,可以利用位运算中的与(|)操作,如果是a则左移0位,如果是b则左移1位...z则左移25位。然后不断取与运算,利用与的性质只要有一个为1这个数就为1。

如:字符串s=abc,开始map[u][v]=0;遇到a时,取与map[u][v]|=1<<(s[0]-'a'),将最后一位变为1,表示a公司可以提供路径,同样处理,可以得到map[u][v]=(111)2=7。

map得到之后,根据Floyd算法,从i到j可以经过某一点k,那么只需取(&)运算(同1才为1),比方说:

 

从1到3,可以经过2,从1到2,可以由abc三个公司提供,从2到3可以由ad提供,我们知道满足条件的只有a,怎么得到结果:

abc    0 1 1 1

ad   &1 0 0 1

-----------------

          0 0 0 1   ----->得到了公共值为a。

如果还有一条路径,如1到3直接有一个b,这样我们可以知道从1到3可以由ab提供,这个时候可以取(|)运算。

a      0 1

b   |  1 0

-----------

        1 1  ------>得到最终结果ab。

运算过程为:map[i][j] | =(map[i][k] & map[k][j]) 。最终结果从i到j只需要看map[i][j]的二进制中的哪一位为1即可。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=210;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int map[MAX][MAX];
int Chg(char *s) //将字符串转换为二进制形式存储
{   int m=0;
    for(int i=0;i<strlen(s);i++)
        m|=1<<(s[i]-'a');
    return m;    
}
void Floyd(int n)
{   for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                map[i][j]|=(map[i][k]&map[k][j]);
}
int main()
{   int n,u,v;
    char s[50]; 
    while(scanf("%d",&n),n)
    {   CLR(map,0);
        while(scanf("%d%d",&u,&v),u+v)
        {   scanf("%s",s);
            map[u][v]=Chg(s); 
        }
        Floyd(n);
        while(scanf("%d%d",&u,&v),u+v)
        {   int flag=1;
            for(int i=0;i<26;i++)
                if(map[u][v]&(1<<i))
                {   printf("%c",i+'a');
                    flag=0;
                }
            if(flag) printf("-");
            printf("\n");            
        }
        printf("\n");
    }
    return 0;
}

题2:Tyvj 1423(拉绳子)

#include<iostream>
#include<cstring>
#include<cstdio> 
#include<algorithm>
using namespace std;
const int MAX=110;
const int Inf=1000010; 
int n,m,map[MAX][MAX];
void Floyd()
{   for(int k=1;k<=n;k++) 
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(map[i][j]>map[i][k]+map[k][j]) 
                    map[i][j]=map[i][k]+map[k][j];
}
int main()
{   int u,v;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)
    {   fill(map[i],map[i]+MAX,Inf);
        map[i][i]=0; 
    }
    for(int i=0;i<m;i++)
    {   scanf("%d%d",&u,&v);
        map[u][v]=map[v][u]=1; 
    }
    Floyd();
    int max=0;
    for(int i=1;i<=n;i++) 
        for(int j=1;j<=n;j++)
            if(max<map[i][j]) max=map[i][j];
    printf("%d\n",max);        
    return 0;
} 



 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值