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的主要内容,如果未能解决你的问题,请参考以下文章

大力飞砖之DFS与并查集(中-下)

CodeForces 731C Socks (DFS或并查集)

1013 Battle Over Cities (25分) DFS | 并查集

tarjan求lca :并查集+dfs

图论:DFS,BFS,邻接链表,并查集

hdu 1198 Farm Irrigation(深搜dfs || 并查集)