求将n*m个点染黑的最小花费值的问题

原题链接
给出n * m(n,m<=5000)个点,起初每个点都是白色的,可以通过花费该点的权重来给该点染黑。对于一个含4个点的小正方形,若三个点是黑色的,则可以花费0值来给第四个点染色。求最终将全部点染黑的最小花费值。
分析:
若某行已染黑,则只需随意向下染一格即可将整条下行均染黑。(列同理)
因此经过分析,易知要染n*m个点,实际只需染n+m个点。
在一个小正方形中,染了三个任意点,等价于将该两行的行号、该两列的列号这四个数并入一个集合,此时第四个点随之被染黑。
故对于每个点,存储行号,列号,权重,然后根据类似最小生成树的思想将每行每列都并入一个集合即可。

struct A{
    int x,y;
    LL val;
    bool operator < (const A & u) const { return val < u.val; }
}a[maxv];
int fa[5010*2];
int getFa(int x){
    if(x==fa[x]) return x;
    return fa[x]=getFa(fa[x]);
}
bool cmp(const A &a,const A &b){return a.val<b.val;}
int main(){
    int n,m,aa,b,c,d,p,cnt;
    LL ans=0;
    n=read(),m=read(),aa=read(),b=read(),c=read(),d=read(),p=read();
    a[0]={0,0,(LL)aa},cnt=n+m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            int ind=(i-1)*m+j;
            a[ind]={i,j+n,(a[ind-1].val*a[ind-1].val*b+a[ind-1].val*c+d)%p};
        }
    for(int i=1;i<=n+m;i++) fa[i]=i;
    sort(a+1,a+n*m+1);
    if(cnt!=1)
    for(int i=1;i<=n*m;i++){
        int faX=getFa(a[i].x),faY=getFa(a[i].y);
        if(faX==faY) continue;
        fa[faX]=faY,cnt--,ans+=a[i].val;
        if(cnt==1) break;
    }
    write(ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值