2/21 并查集+dfs
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2/21 并查集+dfs相关的知识,希望对你有一定的参考价值。
https://www.luogu.com.cn/problem/P2212
并查集建边,点边转换
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e7+5;
struct node
int x,y,dis;
e[maxn];
struct Edge
int u,v,dis;
edge[maxn];
int n,c,f[maxn],cnt,ans,g;
void add(int from,int to,int dis)
edge[++cnt].u=from;
edge[cnt].v=to;
edge[cnt].dis=dis;
bool cmp(Edge e1,Edge e2)
return e1.dis<e2.dis;
int dd(int x1,int y1,int x2,int y2)
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
int r_find(int r)
if(r!=f[r])
f[r]=r_find(f[r]);
return f[r];
void kruskral()
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=cnt;i++)
int fx=r_find(edge[i].u),fy=r_find(edge[i].v);
if(fx==fy)
continue;
f[fx]=fy;
ans+=edge[i].dis;
g++;
if(g==n-1) break;
signed main()
scanf("%lld%lld",&n,&c);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&e[i].x,&e[i].y);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
int tmp=dd(e[i].x,e[i].y,e[j].x,e[j].y);
if(tmp>=c)
add(i,j,tmp);
sort(edge+1,edge+1+cnt,cmp);
kruskral();
if(g==n-1)
cout<<ans<<endl;
else
cout<<-1<<endl;
return 0;
并查集:从一个图像四周建边,对距离排序
通过size
数据来记录生成树中的元素个数
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+5;
int mp[505][505],n,cnt,g,f[maxn],ans,sz[maxn];
int dx[4]=0,1,0,-1;
int dy[4]=-1,0,1,0;
struct node
int u,v,dis;
e[maxn];
void add(int from,int to,int dis)
e[++cnt].u=from;
e[cnt].v=to;
e[cnt].dis=dis;
bool cmp(node e1,node e2)
return e1.dis<e2.dis;
int r_find(int r)
if(r!=f[r])
f[r]=r_find(f[r]);
return f[r];
void kruskral()
for(int i=1;i<=maxn;i++) //*****
f[i]=i,sz[i]=1;
for(int i=1;i<=cnt;i++)
int fx=r_find(e[i].u),fy=r_find(e[i].v);
if(fx==fy)
continue;
f[fx]=fy;
sz[fy]+=sz[fx]; //********合并
if(sz[fy]>=(n*n+1)/2)
cout<<e[i].dis<<endl;
break;
signed main()
scanf("%lld",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%lld",&mp[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<4;k++) //****四周建图
int nx=i+dx[k],ny=j+dy[k];
if(nx<=0||nx>n||ny<=0||ny>n)
continue;
add(i*n+j,nx*n+ny,abs(mp[i][j]-mp[nx][ny]));
sort(e+1,e+cnt+1,cmp);
kruskral();
return 0;
dfs
又犯了低级错误,是const double
,搜索所有油滴的摆放可能,算出每个油滴的最小半径,最后取个极大值。
四舍五入的小技巧,加上0.5在转换成int类型,很棒
#include <bits/stdc++.h>
#define y1 y11
using namespace std;
const int maxn=1e2+5;
const double pi=3.1415926;
int n,area,a[maxn][5],x1,x2,y1,y2;
double mx,h[maxn],res;
bool v[maxn];
double dis(int xx1,int yy1,int xx2,int yy2)
return sqrt((xx1-xx2)*(xx1-xx2)*1.0+(yy1-yy2)*(yy1-yy2)*1.0);
double dd(int k)
for(int i=1;i<=n;i++)
if(i!=k&&v[i]==1)
if(dis(a[k][1],a[k][2],a[i][1],a[i][2])<h[i])
return 0;
double ans=min(min(abs(a[k][1]-x1),abs(a[k][1]-x2)),min(abs(a[k][2]-y1),abs(a[k][2]-y2)));
for(int i=1;i<=n;i++)
double dist;
if(i!=k&&v[i]==1)
dist=dis(a[k][1],a[k][2],a[i][1],a[i][2])-h[i];
ans=min(dist,ans);
return ans;
void dfs(int k,double res)
if(k==n)
mx=max(mx,res);return;
for(int i=1;i<=n;i++)
if(v[i]==0)
h[i]=dd(i);
v[i]=1;
dfs(k+1,res+h[i]*h[i]*pi);
h[i]=0;
v[i]=0;
int main()
scanf("%d",&n);
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
area=abs(x1-x2)*abs(y1-y2);
//cout<<area<<endl;
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i][1],&a[i][2]);
dfs(0,0);
cout<<int(area-mx+0.5)<<endl;
return 0;
以上是关于2/21 并查集+dfs的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces 731C Socks (DFS或并查集)