无向图最小环问题

开端源于一个题:http://oj.coder.ac.cn/problem/INT2007

题意:

给定一些数作为图中的一个点,如果这些数中的某个二进制位相同,则两个数能进行连接,也就是图上的两个点能进行连接。

最终需要我们求的是,图中的这些点形成的最小的环上的点的个数,如果没有形成环,输出-1。

首先我们可以知道的是,如果有超过3个数的二进制位相同,那么最小环一定是3,因为这三个数一定能彼此相连(完全图),所以直接就是上。如果没有超过三个数二进制位相同,就需要将图构建出来,搜索出最小环。

 

这个题的数据量比较小,可以直接使用搜索进行结局,因为某一个二进制位最多只有两个数,按照数据范围来说,最多也就只有60多条边,直接搜索就可以解决。

#include
#include
#define MAX 128
#define max(x,y) x > y ? x : y
#define min(x,y) x < y ? x : y
#define ll long long
// 保存第i个点能到达的二进制位
int map1[MAX][70];
// 保存某个二进制位一能到达的点i
// 最多到达两个点,为什么?因为如果某个二进制位能到达的点超过三个,直接就输出3了,就不用保存图了
int map2[70][2];
int vis[MAX];
int res = 1000005;
// 保存第i个二进制位为1的数的个数
int nums[70];
// 保存最大的二进制位
int maxK = 1;
int main()
{
    memset(nums,0,sizeof(nums));
    memset(map1,0,sizeof(map1));
    memset(map2,0,sizeof(map2));
    memset(vis,0,sizeof(vis));
    int n;
    scanf("%d",&n);
    for(int i=0;i= 3){
                    printf("3\n");
                    return 0;
                }
                map2[k][nums[k]] = i;
                // 二进制的第k位的数字的个数加1
                nums[k]++;
                map1[i][k] = 1;
            }
            c >>= 1;
            k++;
        }
        maxK = max(k,maxK);
    }
    // 搜索,依次以某个二进制位的数为起点
    for(int i=1;i<=maxK;i++){
        int next = map2[i][j];
        vis[next] = 1;
        dfs(i,next,-1,1,1);
        vis[next] = 0;
        // 最小的就是3,所以可以直接结束
        if(res == 3){
            printf("3\n");
            return 0;
        }
        
    }
    if(res == 1000005){
        printf("-1\n");
    }else{
        printf("%d\n",res);
    }
    return 0;
}

// index:当前在哪一个二进制位上,cur,当前的点,pre,前一个点,count,环上的个数,c当前二进制位使用了几次
void dfs(int index,int cur,int pre,int count,int c){
    for(int i=1;i<=maxK;i++){
        // 搜索当前点能到达的下一个点
        if(map1[cur][i]){
            // 如果当前二进制位使用超过两次就必须跳转到其他二进制位上继续往下搜索
            // 因为进行搜索就说明了一个二进制位最多有两个相同的数字,所以最多在一个二进制位上停留两次
            if(c == 2 && index == i){
                c = 0;
                continue;
            }
            for(int j=0;j

 

过是过了,但是感觉效率非常的低,这个题的本质就是一个最小环问题,但是因为数据特殊,所以可以直接使用搜索解决问题,但是如果数据极端的情况下就不行了,最后知道了floyd可以用来解决最小环问题。 

floyd的基本思想是,假设这个环存在,那么一定能通过环上的两个点,找到这个环的值。

算法的证明
设一个环中的最大结点为k(编号最大), 与他相连的两个点为i, j, 那么这个环的最短长度为g[i][k]+g[k][j]+(i到j的路径中所有结点编号都小于k的最短路径长度)。根据floyd的原理, 在最外层循环做了k-1次之后, dist[i][j]则代表了i到j的路径中所有结点编号都小于k的最短路径综上所述,该算法一定能找到图中最小环。

算法模板题:HDU1599

#include
#include
#include
 
using namespace std;
const int maxn = 105;
const int inf = 1e8;
int n,m;
int dis[maxn][maxn],mp[maxn][maxn];//dis表示最短路径,mp表示两点间直线距离(题中给出的值存入mp) 
void floyd(){
    int MinCost = inf;
    for(int k=1;k<=n;k++){
        for(int i=1;i

 

你可能感兴趣的:(算法)