zoukankan      html  css  js  c++  java
  • LOJ#2977. 「THUSCH 2017」巧克力(斯坦纳树+随机化)

    题目

    题目

    做法

    • 考虑部分数据(颜色较少)的:

    二分中位数(mid),将(v[i]=1000+(v[i]>mid))

    具体二分操作:然后求出包含(K)种颜色的联通快最小的权值和,判断该权值和是否满足中位数为(mid),从而调整范围

    其中求权值和显然可以用斯坦纳树解决

    • 正解:

    我们每次随机把颜色映射到([0,K))中去,每次得到的结果正确率就为答案联通块的离散颜色正好一一对应的概率:(frac{K!}{K^K})

    随机(233)次,有(99\%)以上的正确率

    Code

    #include<bits/stdc++.h>
    #include<queue>
    typedef int LL;
    const LL dx[]={0,-1,0,1,0},dy[]={0,0,1,0,-1};
    const LL maxn=7e4+9,inf=1e8;
    inline LL Read(){
        LL x=0,f=1; char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-') f=-1; c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=(x<<3)+(x<<1)+c-'0',c=getchar();
        }
        return x*f;
    }
    std::queue<LL> que;
    LL n,m,T,K,C,tot;
    LL f[maxn][109],c[maxn],sta[maxn],d[maxn][2],a[maxn],pos[255][255],v[maxn],hs[maxn];
    inline bool Ok(LL x,LL y){
    	return x>=1 && x<=n && y>=1 && y<=m;
    }
    inline void Spfa(LL bit){
    	for(LL i=1;i<=tot;++i) if(c[i]!=-1) que.push(i);
    	while(que.size()){
    		LL now(que.front()); que.pop();
    		LL x(d[now][0]),y(d[now][1]);
    		for(LL i=1;i<=4;++i){
    			LL xx(x+dx[i]),yy(y+dy[i]),to(pos[xx][yy]);
    			if(!Ok(xx,yy) || c[to]==-1) continue;
    			if(f[to][bit]>f[now][bit]+a[to]){
    				f[to][bit]=f[now][bit]+a[to];
    				que.push(to);
    			}
    		}
    	}
    }
    inline LL Solve(LL up){
    	for(LL i=0;i<up;++i)
    	    for(LL j=1;j<=tot;++j)
    	        f[j][i]=inf;
    	for(LL i=1;i<=tot;++i) if(c[sta[i]]!=-1) f[i][1<<hs[c[i]]]=a[i];
    	for(LL bit=1;bit<up;++bit){
    		for(LL i=1;i<=tot;++i){
    			LL x(i);
    			if(c[x]==-1) continue;
    			for(LL bit1=(bit-1)&bit;bit1;bit1=(bit1-1)&bit)
    				f[x][bit]=std::min(f[x][bit],f[x][bit1]+f[x][bit-bit1]-a[x]);
    		}
    		Spfa(bit);
    	}
    	LL ans(inf);
    	for(LL i=1;i<=tot;++i) ans=std::min(ans,f[i][up-1]);
    	return ans;
    }
    int main(){
    	srand(time(NULL));
    	T=Read();
    	while(T--){
    		n=Read(); m=Read(); K=Read(); tot=0;
    		sta[0]=0;
    		C=0;
    		for(LL i=1;i<=n;++i)
    		    for(LL j=1;j<=m;++j){
    				pos[i][j]=++tot;
    				d[tot][0]=i; d[tot][1]=j;
    			}
    		for(LL i=1,now=0;i<=n;++i)
    		    for(LL j=1;j<=m;++j){
    		    	LL col(Read());
    				c[++now]=col;//col
    				C=std::max(C,col);
    		    }
    		for(LL i=1,now=0;i<=n;++i)
    		    for(LL j=1;j<=m;++j)
    		        v[++now]=Read();//val
    	    LL up(1<<K),ans1(inf),ans2(inf);
    	    for(LL i=1;i<=233;++i){
    	    	for(LL j=1;j<=C;++j) hs[j]=rand()%K;
    	    	LL l(0),r(1000000),a1(inf),a2(inf);
    	    	while(l<=r){
    	    		LL mid(l+r>>1);
    	    		for(LL i=1;i<=tot;++i) a[i]=(c[i]==-1?inf:1000+(v[i]>mid));
    	    		LL now(Solve(up));
    	    		if(now==inf) break;
    	    		a1=now/1000;
    				LL small(a1-(now-a1*1000));
    	    		if(small>=(a1+1>>1)){
    	    			a2=mid; r=mid-1;
    				}else l=mid+1;
    			}
    			if(a1<ans1 || (a1==ans1 && a2<ans2)){
    				ans1=a1; ans2=a2;
    			}
    		}
    		if(ans1==-1) puts("-1 -1");
    		else printf("%d %d
    ",ans1,ans2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    登录校验
    com.sd.utils/Druidutils.java-连接池
    软件开发流程
    JSP九大内置对象
    . net程序员应该会什么(转载自知乎博主:专注.net领域极客)
    WPF 在属性栏中更改相关设置
    office 2016 专业版 删除部分组件
    AutoMapper安装及基本用法
    sql 求一张表中 列值重复中的 不同列值中的更新时间最大值对应的 全列数据,即相同的列值取时间最晚的哪一行
    C# 多线程 lock
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10832309.html
Copyright © 2011-2022 走看看