Codechef:Find a special connected block/CONNECT(斯坦纳树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/83116632

传送门

题解:
这道题真tm恶心啊。

颜色数小就直接斯坦树了,颜色大的话则考虑给每个颜色随机映射到 [ 1 , K ] [1,K] 的颜色中,这样的正确率就是 K ! K K \frac{K!}{K^K} ,概率大概在0.006。多随机几次就过了。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=17, M=(1<<7)+20, B=1e5+50, inf=1e9, T=550;
const int fx[]={0,0,-1,1};
const int fy[]={1,-1,0,0};
int n,m,tot,k,bin[N],ans=inf;
#define gi(x,y) ((x-1)*m+y)
int f[N*N][M],c[N*N],v[N*N],w[N*N];
int g[N*N],vt[N*N*8],nt[N*N*8],ec;
int q[B],exi[N*N],r;
inline void add(int x,int y) {nt[++ec]=g[x]; g[x]=ec; vt[ec]=y;}
struct data {
	int x,y,w;
	data(int x,int y,int w) : x(x),y(y),w(w) {}
};
inline unsigned int unit() {
	static unsigned int x=2333;
	x^=(x<<5);x^=(x>>17);x^=(x<<13);
	return x;
}
inline void solve() {
	for(int i=1;i<=tot;i++) 
		for(int sta=0;sta<bin[k];sta++) 
				f[i][sta]=inf;
	map <int,int> id;
	for(int i=1;i<=tot;i++) if(c[i]>0) {
			if(!id.count(c[i])) id[c[i]]=unit()%k;
			v[i]=id[c[i]];
		}
	for(int i=1;i<=tot;i++) 
			if(~c[i]) f[i][0]=w[i];
	for(int sta=0;sta<bin[k];sta++) {
		for(int i=1;i<=tot;i++) if(~c[i]) {
				if(c[i] && (sta&bin[v[i]])) f[i][sta]=min(f[i][sta],f[i][sta^bin[v[i]]]);
				for(int s=sta;s>sta^s;s=(s-1)&sta) 
					f[i][sta]=min(f[i][sta],f[i][s]+f[i][sta^s]-w[i]);
			}
		r=0;
		for(int i=1;i<=tot;i++) if(~c[i])
				if(f[i][sta]<ans) q[++r]=i, exi[i]=1;
		for(int i=1;i<=r;i++) {
			int u=q[i], uw=f[u][sta]; exi[u]=0;
			for(int e=g[u];e;e=nt[e]) {
				int v=vt[e];
				if(~c[v] && f[v][sta]>uw+w[v]) {
					f[v][sta]=uw+w[v];
					if(!exi[v] && f[v][sta]<ans) exi[v]=1, q[++r]=v;
				}
			}
		}
	}
	for(int i=1;i<=tot;i++) ans=min(ans,f[i][bin[k]-1]);
}
int main() {
	n=rd(), m=rd(), k=rd(); tot=n*m;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) c[gi(i,j)]=rd();
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) w[gi(i,j)]=rd();
	for(int i=0;i<=k;i++) bin[i]=1<<i;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(~c[gi(i,j)]) for(int z=0;z<4;z++) {
		int i2=i+fx[z], j2=j+fy[z]; 
		if(i2<1 || i2>n || j2<1 || j2>m || !~c[gi(i2,j2)]) continue;
		add(gi(i,j),gi(i2,j2));
	}
	for(int i=T;i;i--) solve();
	printf("%d\n",(ans==inf) ? -1 : ans);
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83116632