最小环

该博客探讨了在无向图中寻找最小环的问题。当两个数相加不等于0时,它们之间可以建立边。如果存在一个数位为1的数出现3次或以上,那么最小环长度为3。当数的个数达到一定阈值时,必然存在3环。博主通过代码展示了如何使用Floyd算法来求解最小环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

无向图最小环:

http://acm.hdu.edu.cn/showproblem.php?pid=1599

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 1005
using namespace std;
ll dp[MAXN][MAXN];
ll dis[MAXN][MAXN];

/*
无向图的最短路
*/

ll floyd(int n)
{
     /*
    未更新的dis[i][j]是没有经过k点的,加个k点,就是最少三点的最小环
    */
    ll res=1e14;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
            for(int j=i+1;j<k;j++)
                res=min(res,dis[i][j]+dp[i][k]+dp[k][j]);

        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
    return res;
}

int main()
{
    int n,m,w,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
        dp[i][j]=dp[j][i]=dis[i][j]=dis[j][i]=1e14;

        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d%d",&a,&b,&w);
            dis[a][b]=min(dis[a][b],(ll)w);//注意重边
            dp[a][b]=dp[b][a]=dis[b][a]=dis[a][b];
        }
        ll res=floyd(n);
        if(res<1e14)
            printf("%lld\n",res);
        else
            printf("It's impossible.\n");
    }
    return 0;
}

最小环输出路径

https://cn.vjudge.net/problem/POJ-1734

代码:

#include<iostream>
#include<cstdio>
#define ll long long
#define MAXN 1005
using namespace std;
ll dp[MAXN][MAXN];
ll dis[MAXN][MAXN];

/*
无向图的最短路
*/

int cnt;
int path[MAXN];
int pre[MAXN][MAXN];
int p;

ll floyd(int n)
{
    /*
    未更新的dis[i][j]是没有经过k点的,加个k点,就是最少三点的最小环
    */
    ll res=1e12;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
            for(int j=i+1;j<k;j++)
            {
                if(dis[i][j]+dp[i][k]+dp[k][j]<res)
                {
                    res=dis[i][j]+dp[i][k]+dp[k][j];
                    p=j,cnt=0;
                    while(p!=i){
                        path[++cnt]=p;
                        p=pre[i][p];
                    }
                    path[++cnt]=i;
                    path[++cnt]=k;
                }
            }

        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(dis[i][j]>dis[i][k]+dis[k][j])
                {
                    dis[i][j]=dis[i][k]+dis[k][j];
                    pre[i][j]=pre[k][j];
                }
                
    }
    return res;
}

int main()
{
    int n,m,w,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
        dp[i][j]=dp[j][i]=dis[i][j]=dis[j][i]=1e12,pre[i][j]=i;

        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d%d",&a,&b,&w);
            dis[a][b]=min(dis[a][b],(ll)w);//注意重边
            dp[a][b]=dp[b][a]=dis[b][a]=dis[a][b];
        }
        cnt=0;
        ll res=floyd(n);
        if(res<1e12)
        {
            for(int i=1;i<cnt;i++)
                printf("%d ",path[i]);
            printf("%d\n",path[cnt]);
        }
        else
            printf("No solution.\n");
    }
    return 0;
}

Shortest Cycle

题意:

给定n个数,如果两数或起来不为0,呢么就可以在两数之间建一条边

求这个图的最小环

解析:

考虑非0的数,首先数位最多63位,如果在一个数位是1的数有3个及以上,呢么最小环就是3

如果数的个数>=(log2(1e18)),呢么必定有3环

否则,我们建图,用floyd计算最小环

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
ll a[MAXN];
ll m[MAXN];
ll mp[201][201];
ll dp[201][201];
ll res=1e9;

void floyd(int n)
{
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<k;i++)
			for(int j=i+1;j<k;j++)
				res=min(res,dp[i][j]+mp[i][k]+mp[k][j]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				dp[i][j]=dp[j][i]=min(dp[i][j],dp[i][k]+dp[k][j]);
	}
}

int main()
{
    int k=0,n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        if(a[i]!=0)
            m[++k]=a[i];
    }
    if(k>=120)
    {
        printf("3\n");
    }
    else{
        for(int i=0;i<=200;i++)
        for(int j=0;j<=200;j++)
                dp[i][j]=mp[i][j]=1e9;
        n=k;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if((m[i]&m[j])!=0&&i!=j)
                {
                    mp[i][j]=mp[j][i]=dp[i][j]=dp[j][i]=1;
                }
        floyd(n);
        if(res>=1e9)
            printf("-1\n");
        else printf("%lld\n",res);
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值