3/25《并查集》

P1892 [BOI2003]团伙
数组记录敌人;且在每次合并前,先合并别人的敌人

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e4+5;
int p[maxn],f[maxn],n,m;
int r_find(int r)
{
    if(f[r]==r)
        return r;
    f[r]=r_find(f[r]);
    return f[r];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
    {
        char c;int a,b;
        cin>>c>>a>>b;
        if(c=='F')
        {
            int fx=r_find(a),fy=r_find(b);
            f[fx]=fy;
        }
        if(c=='E')
        {
            if(p[a])
            {
                int fx=r_find(p[a]),fy=r_find(b);
                f[fx]=fy;
            }
            if(p[b])
            {
                int fx=r_find(a),fy=r_find(p[b]);
                f[fx]=fy;
            }
            p[a]=b,p[b]=a; //存储敌人
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i) ans++;
    }
    cout<<ans<<endl;
    return 0;
}

P1955 [NOI2015] 程序自动分析
离散化处理+并查集。。。。思路是不难,但这离散化处理确实麻烦
1.进行排序,然后去重。
2.lowerbound进行下标的查找

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
int f[maxn],book[maxn*3],n,m;
struct node
{
    int x,y,z;
}e[maxn];
bool cmp(node e1,node e2)
{
    return e1.z>e2.z;
}
int r_find(int r)
{
    if(f[r]==r)
        return r;
    f[r]=r_find(f[r]);
    return f[r];
}
signed main()
{
    int t;cin>>t;
    while(t--)
    {
        int tol=0;cin>>n;
        memset(book,0,sizeof(book));
        for(int i=1;i<=n;i++){
            cin>>e[i].x>>e[i].y>>e[i].z;
            book[++tol]=e[i].x,book[++tol]=e[i].y;
        }
        sort(book+1,book+tol+1);
        int cnt=unique(book+1,book+tol+1)-book-1;
        for(int i=1;i<=n;i++)
        {
            e[i].x=lower_bound(book+1,book+cnt+1,e[i].x)-book;
            e[i].y=lower_bound(book+1,book+cnt+1,e[i].y)-book;
        }
        for(int i=1;i<=cnt;i++) f[i]=i;
        int flag=1;
        sort(e+1,e+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            int fx=r_find(e[i].x),fy=r_find(e[i].y);
            if(e[i].z==1)
                f[fx]=fy;
            else if(e[i].z==0)
            {
                if(fx==fy)
                {
                    cout<<"NO"<<endl;flag=0;break;
                }
            }
        }
        if(flag)
            cout<<"YES"<<endl;
    }

    return 0;
}

P1991 无线通讯网
主要是对于电话的处理。共p个灯塔,需要p-1条边,最后的(s-1)个边放电话。

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
int f[maxn],s,p,a[maxn],b[maxn],cnt;
struct node
{
    int x,y;double dis;
}e[maxn];
bool cmp(node e1,node e2)
{
    return e1.dis<e2.dis;
}
int r_find(int r)
{
    if(f[r]==r)
        return r;
    f[r]=r_find(f[r]);
    return f[r];
}
double cal(int x1,int y1,int x2,int y2)
{
    return (double)sqrt((x1-x2)*(x1-x2)*1.0+(y1-y2)*(y1-y2)*1.0);
}
signed main()
{
    scanf("%d%d",&s,&p);
    for(int i=1;i<=p;i++)
        scanf("%d%d",&a[i],&b[i]);
    for(int i=1;i<p;i++)
        for(int j=i+1;j<=p;j++)
    {
        e[++cnt].x=i,e[cnt].y=j,e[cnt].dis=cal(a[i],b[i],a[j],b[j]);
    }
    sort(e+1,e+cnt+1,cmp);
    for(int i=1;i<=p;i++) f[i]=i;
    int ans=0;
    for(int i=1;i<=cnt;i++)
    {
        int fx=r_find(e[i].x),fy=r_find(e[i].y);
        if(fx!=fy)
        {
            f[fx]=fy;ans++;
            if(ans>=(p-1)-(s-1))
            {
                ans=i;break;
            }
        }
    }
    cout<<fixed<<setprecision(2)<<e[ans].dis<<endl;
    return 0;
}

背包

举例:10000个物品利用二进制优化,拆分成1,2,4,8,16,32,64,128……个,剩下的不满则10000去减。

int t=1;
while(x>=t)
{
    v[cnt]=a*t;
    c[cnt++]=b*t;
    x-=t;t<<=1;
}
if(x)
{
    v[cnt]=a*x;
    b[cnt++]=b*x;
}

P2170 选学霸
难点在于背包的处理。
记得学一下bitset优化的01背包!!!

#include <bits/stdc++.h>

using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
int f[maxn],n,m,k,sz[maxn],p[maxn],cnt,dp[maxn];
int r_find(int r)
{
    if(f[r]==r)
        return r;
    f[r]=r_find(f[r]);
    sz[r]=sz[f[r]];
    return f[r];
}
signed main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) f[i]=i,sz[i]=1;
    for(int i=1;i<=k;i++)
    {
        int a,b;cin>>a>>b;
        int fx=r_find(a),fy=r_find(b);
        if(fx!=fy)
        {
            f[fx]=fy;
            sz[fx]+=sz[fy];
            sz[fy]=sz[fx];
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i)
        {
            p[++cnt]=sz[i];
        }
    }
    dp[0]=true;
    for(int i=1; i<=cnt; i++)
        for(int j=n; j>=p[i]; j--)
            if(!dp[j]&&dp[j-p[i]])
                dp[j]=true;
    int ans=inf,minn=inf;
    for(int i=0; i<=n; i++)
        if(dp[i]&&abs(i-m)<minn) minn=abs(i-m),ans=i;
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值