• 【THUSC2017】【LOJ2977】巧克力 斯坦纳树


    题目大意

      有一个网格(或者你可以认为这是一个图),每个点都有颜色 (c_i) 和点权 (a_i)

      求最小的连通块,满足这个连通块内点的颜色数量 (geq k)。在满足点数最少的前提下,要求点权的中位数最少。

      (nleq 233,c_ileq n,kleq 5)

    题解

      如果 (c_i) 很小,就可以直接用斯坦纳树做。

      本题要求在满足点数最少的前提下,要求点权的中位数最少。那么可以二分中位数 (s),将 (a_ileq s) 的点的权值设为 (M-1)(a_i>s) 的点的权值设为 (M+1),其中 (M) 是一个很大的数。这样就可以在满足点数最小的前提下求出最小中位数是否 (leq s)

      还有一个问题是 (c_i) 比较大。我们可以把每一种颜色随机映射到 ([1,k]) 中,当答案的 (k) 种颜色映射到 ([1,k]) 中不同的值的时候就能求出正确答案。求一次正确的概率是 (frac{k!}{k^k}),多求几次就好了。

      时间复杂度:(O(T(3^kn+2^knlog n)log n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<functional>
    #include<cmath>
    #include<vector>
    #include<assert.h>
    #include<queue>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef long double ldb;
    typedef std::pair<int,int> pii;
    typedef std::pair<ll,ll> pll;
    void open(const char *s){
    #ifndef ONLINE_JUDGE
    	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
    #endif
    }
    void open2(const char *s){
    #ifdef DEBUG
    	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
    #endif
    }
    int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
    void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
    int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
    int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
    const int inf=0x3fffffff;
    const int N=300;
    int _n,_m;
    int n,k;
    int t;
    int a[N],c[N],d[N],e[N],b[N],vis[N];
    int a2[N],c2[N];
    int f[1<<5][N];
    vector<int> g[N];
    pii ans;
    queue<pii> q1,q2,q3;
    //priority_queue<pii,vector<pii>,greater<pii> > q;
    int id(int x,int y)
    {
    	return (x-1)*_m+y;
    }
    vector<pii> h;
    int check(int v)
    {
    	for(int i=1;i<=n;i++)
    		if(a[i]<=v)
    			a2[i]=100000-1;
    		else
    			a2[i]=100000+1;
    	for(int i=0;i<1<<k;i++)
    		for(int j=1;j<=n;j++)
    			f[i][j]=inf;
    	for(int i=1;i<=n;i++)
    		if(c2[i]!=-1)
    			f[1<<(c2[i]-1)][i]=0;
    	for(int i=1;i<1<<k;i++)
    	{
    		for(int j=(i-1)&i;j;j=(j-1)&i)
    			for(int l=1;l<=n;l++)
    				f[i][l]=min(f[i][l],f[j][l]+f[i^j][l]);
    		h.clear();
    		for(int j=1;j<=n;j++)
    		{
    			h.push_back(pii(f[i][j],j));
    			vis[j]=0;
    		}
    		sort(h.begin(),h.end());
    		for(int i=0;i<n;i++)
    			q3.push(h[i]);
    		while(!q1.empty()||!q2.empty()||!q3.empty())
    		{
    			pii x;
    			if(!q1.empty()&&(q2.empty()||(q1.front()<=q2.front()))&&(q3.empty()||(q1.front()<=q3.front())))
    			{
    				x=q1.front();
    				q1.pop();
    			}
    			else if(!q2.empty()&&(q1.empty()||(q2.front()<=q1.front()))&&(q3.empty()||(q2.front()<=q3.front())))
    			{
    				x=q2.front();
    				q2.pop();
    			}
    			else
    			{
    				x=q3.front();
    				q3.pop();
    			}
    			if(vis[x.second])
    				continue;
    			vis[x.second]=1;
    			f[i][x.second]=min(f[i][x.second],x.first);
    			x.first+=a2[x.second];
    //			for(auto v:g[x.second])
    			for(vector<int>::iterator it=g[x.second].begin();it!=g[x.second].end();it++)
    			{
    				int v=*it;
    				if(!vis[v])
    				{
    					if(a2[x.second]==100000-1)
    						q1.push(pii(x.first,v));
    					else
    						q2.push(pii(x.first,v));
    				}
    			}
    		}
    	}
    	int res=inf;
    	for(int i=1;i<=n;i++)
    		if(c2[i]!=-1)
    		{
    			f[(1<<k)-1][i]+=a2[i];
    			res=min(res,f[(1<<k)-1][i]);
    		}
    	return res;
    }
    void gao()
    {
    	for(int i=1;i<=n;i++)
    		b[i]=rand()%k+1;
    	for(int i=1;i<=n;i++)
    		if(c[i]!=-1)
    			c2[i]=b[c[i]];
    		else
    			c2[i]=-1;
    	int l=1,r=t;
    	int temp=check(1);
    	if(temp==inf)
    		return;
    	int v=(int)round((db)temp/100000);
    	if(v>ans.first)
    		return;
    	while(l<r)
    	{
    		int mid=(l+r)>>1;
    		temp=check(mid);
    		if(temp<=(int)round((db)temp/100000)*100000)
    			r=mid;
    		else
    			l=mid+1;
    	}
    	ans=min(ans,pii(v,l));
    }
    void solve()
    {
    	scanf("%d%d%d",&_n,&_m,&k);
    	n=_n*_m;
    	for(int i=1;i<=n;i++)
    		scanf("%d",&c[i]);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		d[i]=a[i];
    	}
    	sort(d+1,d+n+1);
    	t=unique(d+1,d+n+1)-d-1;
    	for(int i=1;i<=n;i++)
    		a[i]=lower_bound(d+1,d+t+1,a[i])-d;
    	for(int i=1;i<=n;i++)
    		g[i].clear();
    	for(int i=1;i<=_n;i++)
    		for(int j=1;j<=_m;j++)
    			if(c[id(i,j)]!=-1)
    			{
    				if(i>1&&c[id(i-1,j)]!=-1)
    					g[id(i,j)].push_back(id(i-1,j));
    				if(i<_n&&c[id(i+1,j)]!=-1)
    					g[id(i,j)].push_back(id(i+1,j));
    				if(j>1&&c[id(i,j-1)]!=-1)
    					g[id(i,j)].push_back(id(i,j-1));
    				if(j<_m&&c[id(i,j+1)]!=-1)
    					g[id(i,j)].push_back(id(i,j+1));
    			}
    	ans=pii(inf,inf);
    	for(int times=200;times;times--)
    		gao();
    	if(ans.first==inf)
    		printf("-1 -1
    ");
    	else
    		printf("%d %d
    ",ans.first,d[ans.second]);
    }
    int main()
    {
    	srand(19260817);
    	open("chocolate");
    	int t;
    	scanf("%d",&t);
    	while(t--)
    		solve();
    	return 0;
    }z
    
  • 相关阅读:
    [LeetCode] Search a 2D Matrix
    CCBPM中的消息机制,CCIM服务端安装说明
    程序基石系列之C++多态的前提条件
    汇编中常见的一些错误信息
    浏览器的CSS Hacks
    易学设计模式看书笔记(7)
    [易飞]简易制程日报-月报
    js thiskeyword
    时空-问题集锦(转载)
    Delphi 组件渐进开发浅谈(二)——双简合璧
  • 原文地址:https://www.cnblogs.com/ywwyww/p/10290909.html
Copyright © 2020-2023  润新知