zoukankan      html  css  js  c++  java
  • 浅谈Floyd的三种用法 By cellur925

    Floyd大家可能第一时间想到的是他求多源最短路的n³算法。其实它还有另外两种算法的嘛qwq。写一发总结好了qwq。

    一、多源最短路

    放段代码跑,注意枚举顺序,用邻接矩阵存图。本质是一种动规。

    复杂度O(n³)。

    1 for(int k=1;k<=n;k++)
    2     for(int i=1;i<=n;i++)
    3         for(int j=1;j<=n;j++)
    4             f[i][j]=min(f[i][j],f[i][k]+f[k][j]); 
    View Code

    放个例题跑。

    灾后重建

    二、传递闭包

    在交际网络中,给定若干个元素,若干个二元关系,关系有传递性。传递闭包就是一种“通过传递性推导出尽量多的元素之间关系的问题”,求出可确定排名的元素个数。

    实现用一个布尔型的邻接矩阵,f[i][j]=1表示i与j有关系,否则则没有关系。

    我们每次可以枚举k点,来解决那些间接相关的关系处理。

    1 for(int k=1;k<=n;k++)
    2     for(int i=1;i<=n;i++)
    3         for(int j=1;j<=n;j++)
    4             f[i][j]|=f[i][k]&f[k][j]; 
    View Code

    例题 [USACO08JAN]牛大赛Cow Contest

    对于奶牛的编程能力,用f[i][j]=1表示i比j强,之后就是一个裸的传递闭包。跑一遍后n²统计每只牛它与其他牛的关系是否已经确定,意思就是说只要有f[i]j]=1或f[j][i]=1其中一个就行,来统计答案。

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,m,ans;
     7 int f[200][200];
     8 
     9 int main()
    10 {
    11     scanf("%d%d",&n,&m);
    12     for(int i=1;i<=m;i++)
    13     {
    14         int x=0,y=0;
    15         scanf("%d%d",&x,&y);
    16         f[x][y]=1;
    17     }
    18     for(int k=1;k<=n;k++)
    19         for(int i=1;i<=n;i++)
    20             for(int j=1;j<=n;j++)
    21                 f[i][j]|=f[i][k]&f[k][j];
    22     for(int i=1;i<=n;i++)
    23     {
    24         int j;
    25         for(j=1;j<=n;j++)
    26         {
    27             if(i==j) continue;
    28             if(f[i][j]==0&&f[j][i]==0) break;
    29         }
    30         if(j>n) ans++;
    31     }
    32     printf("%d",ans);
    33     return 0;
    34 }
    View Code

    三、求无向图最小环

    例题1 USACO4.1篱笆回路 

    这道题难在建图,图建好以后就是裸的跑floyd找最小环了。

    (瞎说一句,这题竟然有个数组开了1000的空间,但是越界了呀qwq)

    Code

     1 /*
     2 ID:cellur_2
     3 TASK:fence6
     4 LANG:C++
     5 */
     6 #include<cstdio>
     7 #include<algorithm>
     8 #include<cstring>
     9 
    10 using namespace std;
    11 const int inf=0x3f3f3f3f;
    12 
    13 int n,num,ans=inf;
    14 int dis[300][300],mapp[300][300];
    15 struct node{
    16     int len;
    17     int lcnt,rcnt,lid,rid,id;
    18     int l[300],r[300];
    19 }edge[300];
    20 
    21 int main()
    22 {
    23     scanf("%d",&n);
    24     for(int i=1;i<=n;i++)
    25     {
    26         scanf("%d",&edge[i].id);
    27         int x=edge[i].id;
    28         scanf("%d",&edge[x].len);
    29         scanf("%d%d",&edge[x].lcnt,&edge[x].rcnt);
    30         for(int j=1;j<=edge[x].lcnt;j++)
    31             scanf("%d",&edge[x].l[j]);
    32         for(int j=1;j<=edge[x].rcnt;j++)
    33             scanf("%d",&edge[x].r[j]);
    34     }
    35     for(int i=1;i<=n;i++)
    36     {// lid  这条边左端点的点编号
    37      // rid  这条边右端点的点编号  
    38         if(!edge[i].lid) edge[i].lid=++num;
    39         for(int j=1;j<=edge[i].lcnt;j++)
    40         {
    41             int x=edge[i].l[j];
    42             bool flag=0;
    43             for(int k=1;k<=edge[x].lcnt;k++)
    44                 if(edge[x].l[k]==i) 
    45                 {
    46                     flag=1;
    47                     break;
    48                 }
    49             if(flag) edge[x].lid=edge[i].lid;
    50             else edge[x].rid=edge[i].lid;
    51         }
    52         if(!edge[i].rid) edge[i].rid=++num;
    53         for(int j=1;j<=edge[i].rcnt;j++)
    54         {
    55             int x=edge[i].r[j];
    56             bool flag=0;
    57             for(int k=1;k<=edge[x].lcnt;k++)
    58                 if(edge[x].l[k]==i)
    59                 {
    60                     flag=1;
    61                     break;
    62                 }
    63             if(flag) edge[x].lid=edge[i].rid;
    64             else edge[x].rid=edge[i].rid;
    65         }
    66     }
    67     memset(mapp,0x3f,sizeof(mapp));
    68     memset(dis,0x3f,sizeof(dis));
    69     ans=dis[2][33];
    70     for(int i=1;i<=n;i++) mapp[i][i]=0,dis[i][i]=0;
    71     for(int i=1;i<=n;i++)
    72     {
    73         int lid=edge[i].lid;
    74         int rid=edge[i].rid;
    75         int len=edge[i].len;
    76         mapp[rid][lid]=mapp[lid][rid]=len;
    77         dis[rid][lid]=dis[lid][rid]=len;
    78     }    
    79     //floyd找最小环 
    80     for(int k=1;k<=num;k++)
    81     {
    82         for(int i=1;i<k;i++)
    83             for(int j=i+1;j<k;j++)
    84                 ans=min(ans,dis[i][j]+mapp[i][k]+mapp[k][j]);
    85         for(int i=1;i<=num;i++)
    86             for(int j=1;j<=num;j++)
    87                 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    88     }
    89     printf("%d
    ",ans);
    90     return 0;
    91 }
    View Code

     例题2 POJ 1734 Sightseeing Trip

    其实是floyd找最小环的板子题,但是由于题目要求输出一种合法的方案,所以我们只要再开一个vector就行了。

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstring>
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 
     9 int n,m;
    10 int ans=0x3f3f3f3f;
    11 int dis[200][200],mapp[200][200],pos[200][200];
    12 vector<int>path;
    13 
    14 void get_path(int x,int y)
    15 {
    16     if(pos[x][y]==0) return ;
    17     get_path(x,pos[x][y]);
    18     path.push_back(pos[x][y]);
    19     get_path(pos[x][y],y);
    20 }
    21 
    22 int main()
    23 {
    24     scanf("%d%d",&n,&m);
    25     memset(dis,0x3f,sizeof(dis));
    26     for(int i=1;i<=n;i++) dis[i][i]=0;
    27     for(int i=1;i<=m;i++)
    28     {
    29         int x=0,y=0,z=0;
    30         scanf("%d%d%d",&x,&y,&z);
    31         dis[x][y]=dis[y][x]=min(dis[x][y],z);
    32     }
    33     memcpy(mapp,dis,sizeof(dis));
    34     for(int k=1;k<=n;k++)
    35     {
    36         for(int i=1;i<k;i++)
    37             for(int j=i+1;j<k;j++)
    38                 if((ll)mapp[i][j]+dis[j][k]+dis[i][k]<ans) 
    39                 {
    40                     ans=mapp[i][j]+dis[i][k]+dis[k][j];
    41                     path.clear();
    42                     path.push_back(i);
    43                     get_path(i,j);
    44                     path.push_back(j);
    45                     path.push_back(k);
    46                 }
    47         for(int i=1;i<=n;i++)
    48             for(int j=1;j<=n;j++)
    49                 if(mapp[i][j]>mapp[i][k]+mapp[k][j])
    50                 {
    51                     mapp[i][j]=mapp[i][k]+mapp[k][j];
    52                     pos[i][j]=k;
    53                 }
    54     }
    55     if(ans==0x3f3f3f3f) 
    56     {
    57         printf("No solution.");
    58         return 0;
    59     }
    60     for(int i=0;i<path.size();i++)
    61         printf("%d ",path[i]);
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    CF1091E
    jzoj5703
    CF1109F
    杂题
    CF1194F
    杂题
    个人作业1-数组(二维数组)
    第三周-学习进度条
    构建之法阅读笔记02
    个人作业1-数组(续1)
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9590907.html
Copyright © 2011-2022 走看看