无向图最小环:
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;
}
题意:
给定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;
}