题意:
就是在一个二维平面上,给你m条边,每条边给你两个端点和一个边的权值。现在让你找出一个权值和最小的环。
思考:
- 当时看到这题就感觉是之前在桂林做的2021桂林-Buy and Delete,distra求图的最小环。但是那个复杂度是有两种方法,一个是n×m×log(n),一个是m×m×log(n)。但是对于本题来说,这两个复杂度都会超时,但是一般情况下,图论的题目,稍微加点优化剪支就差不多过了。所以用这两种策略也可以。
- 当然有正确的做法,就是先把图的最小生成树跑出来,然后每次枚举没有在生成树中的边,然后求出来这跳边两个端点a和b在最小生成数种的距离,所以对最小生成树求个lca。然后每次就更新环的答案就可以了。
- 不过值得注意的是,倍增的时候,如果多次求倍增,那么是需要初始化的,反正做题的时候,把能初始化的都初始化掉就可以了。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define int long long
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e18;
const int N = 2e5+10,M = 2010;
struct node{
int a,b,c;
}va[N];
int T,n,m,k;
int vis[N],flag[N],sum[N];
int fa[N],acc[N][25],dep[N],cnt = 22;
map<PII,int> mp;
vector<PII > e[N];
void init()
{
mp.clear();
for(int i=0;i<=n;i++)
{
e[i].clear();
flag[i] = sum[i] = 0;
for(int j=0;j<=22;j++) acc[i][j] = 0;
}
for(int i=0;i<=m;i++) vis[i] = 0;
n = 0;
}
int find(int x)
{
if(x!=fa[x]) fa[x] = find(fa[x]);
return fa[x];
}
bool cmp(node A,node B)
{
return A.c<B.c;
}
void krukal()
{
sort(va+1,va+1+m,cmp);
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=1;i<=m;i++)
{
int a = va[i].a,b = va[i].b,c = va[i].c;
int t1 = find(a),t2 = find(b);
if(t1!=t2)
{
vis[i] = 1;
fa[t1] = t2;
e[a].pb({b,c});e[b].pb({a,c});
}
}
}
void dfs(int now,int p)
{
flag[now] = 1;
acc[now][0] = p;
dep[now] = dep[p]+1;
for(int i=1;i<=cnt;i++)
acc[now][i] = acc[acc[now][i-1]][i-1];
for(auto t:e[now])
{
int spot = t.fi,w = t.se;
if(spot==p) continue;
sum[spot] = sum[now]+w;
dfs(spot,now);
}
}
int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
for(int i=cnt;i>=0;i--)
{
if(dep[acc[a][i]]>=dep[b])
a = acc[a][i];
}
if(a==b) return a;
for(int i=cnt;i>=0;i--)
{
if(acc[a][i]!=acc[b][i])
{
a = acc[a][i];
b = acc[b][i];
}
}
return acc[a][0];
}
signed main()
{
IOS;
cin>>T;
for(int cs=1;cs<=T;cs++)
{
init();
cin>>m;
for(int i=1;i<=m;i++)
{
int x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
if(!mp.count({x1,y1})) mp[{x1,y1}] = ++n;
if(!mp.count({x2,y2})) mp[{x2,y2}] = ++n;
int a = mp[{x1,y1}],b = mp[{x2,y2}];
va[i] = {a,b,c};
}
krukal();
for(int i=1;i<=n;i++) if(!flag[i]) dfs(i,0);
int minn = inf;
for(int i=1;i<=m;i++)
{
if(vis[i]) continue;
int a = va[i].a,b = va[i].b,c = va[i].c;
minn = min(minn,c+sum[a]+sum[b]-2*sum[lca(a,b)]);
}
if(minn==inf) minn = 0;
cout<<"Case #"<<cs<<": "<<minn;
if(cs!=T) cout<<"\n";
}
return 0;
}
总结:
多多积累。