「LG7450-巧克力」题解
P7450 [THUSC 2017] 巧克力
sol
首先显然只选 \(k\) 种最优。那么如何解决这个问题呢?
有一种科技叫 color-coding。我们把原有的所有颜色随机映射到 \([0,k)\) 的值域区间上,那么一个包含 \([0,k)\) 内所有颜色的块必然至少包含 \(k\) 种颜色,且这么做得到正确的最小的包含 \(k\) 种颜色的块大小的概率极大。正确性证明可以参见这里。
于是这就是一个最小斯坦纳树问题。
接下来考虑第二问,最小化中位数。这是个经典套路,我们二分中位数按大小新建正负一序列即可。一个 trick 是给一般的 \(-1,1\) 变成 \(999,1001\)(举个例子),这样就能使程序自动在最小化块数的基础上尽可能地选 \(-1\) 块。
记得多测要清空。
code
#define id(x,y) ((x)*mm+(y))
int n,nn,mm,k;
int c[N],a[N],v[N],to[N];
int cx[N],cm;
vec<int> G[N];
int f[N][1<<K];
queue<int> q;
bool inq[N];
void spfa(int s){
	while(!q.empty()){
		int x=q.front();q.pop();inq[x]=0;
		for(auto y:G[x])if(f[y][s]>f[x][s]+v[y]){
			f[y][s]=f[x][s]+v[y];
			if(!inq[y])q.push(y),inq[y]=1;
		}
	}
}
int solve(){
	int res=inf;
	rep(t,1,200){
		shuffle(cx,cx+cm,rnd);
		repl(i,0,cm)to[cx[i]]=i%k;
		repl(i,0,n)repl(j,0,1<<k)f[i][j]=inf;
		repl(i,0,n)if(~c[i])f[i][1<<to[c[i]]]=v[i];
		repl(s,1,1<<k){
			repl(i,0,n)if(~c[i]){
				for(int t=s&s-1;t;t=s&t-1)chmin(f[i][s],f[i][t]+f[i][s^t]-v[i]);
				if(f[i][s]<inf)q.push(i),inq[i]=1;
			}
			spfa(s);
		}
		repl(i,0,n)if(~c[i])chmin(res,f[i][(1<<k)-1]);
	}
	return res;
}
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
inline void Main(){
	read(nn,mm,k);
	cm=0;
	repl(i,0,nn)repl(j,0,mm){read(c[id(i,j)]);if(~c[id(i,j)])cx[cm++]=c[id(i,j)];};
	n=nn*mm;
	sort(cx,cx+cm);cm=unique(cx,cx+cm)-cx;
	repl(i,0,n)if(~c[i])c[i]=lower_bound(cx,cx+cm,c[i])-cx;
	repl(i,0,cm)cx[i]=i;
	repl(i,0,nn)repl(j,0,mm)read(a[id(i,j)]),v[id(i,j)]=!!~c[id(i,j)];
	repl(i,0,nn)repl(j,0,mm)if(~c[id(i,j)])repl(k,0,4){
		int x=i+dx[k],y=j+dy[k];
		if(x<0||x>=nn||y<0||y>=mm||!~c[id(x,y)])continue;
		G[id(i,j)].pub(id(x,y));
	}
	int res=solve();
	if(res==inf)return put((string)"-1 -1");
	int l=0,r=1e6;
	while(l<r){
		int m=l+r>>1;
		repl(i,0,n)v[i]=a[i]<=m?999:1001;
		if(solve()<=res*1000)r=m;
		else l=m+1;
	}
	put(res,' '),put(l,'\n');
	repl(i,0,n)G[i].clear();
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号