博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【THUSC2017】【LOJ2977】巧克力 斯坦纳树
阅读量:5302 次
发布时间:2019-06-14

本文共 3109 字,大约阅读时间需要 10 分钟。

题目大意

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

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

  \(n\leq 233,c_i\leq n,k\leq 5\)

题解

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

  本题要求在满足点数最少的前提下,要求点权的中位数最少。那么可以二分中位数 \(s\),将 \(a_i\leq 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^kn\log n)\log n)\)

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;typedef long long ll;typedef unsigned long long ull;typedef double db;typedef long double ldb;typedef std::pair
pii;typedef std::pair
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;}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
g[N];pii ans;queue
q1,q2,q3;//priority_queue
,greater
> q;int id(int x,int y){ return (x-1)*_m+y;}vector
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<
::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<
ans.first) return; while(l
>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\n"); else printf("%d %d\n",ans.first,d[ans.second]);}int main(){ srand(19260817); open("chocolate"); int t; scanf("%d",&t); while(t--) solve(); return 0;}z

转载于:https://www.cnblogs.com/ywwyww/p/10290909.html

你可能感兴趣的文章
开源网络漏洞扫描软件
查看>>
yum 命令跳过特定(指定)软件包升级方法
查看>>
创新课程管理系统数据库设计心得
查看>>
Hallo wolrd!
查看>>
16下学期进度条2
查看>>
Could not resolve view with name '***' in servlet with name 'dispatcher'
查看>>
Chapter 3 Phenomenon——12
查看>>
C语言中求最大最小值的库函数
查看>>
和小哥哥一起刷洛谷(1)
查看>>
jquery对id中含有特殊字符的转义处理
查看>>
遇麻烦,Win7+Ubuntu12.10+Archlinux12.10 +grub
查看>>
SqlBulkCopy大批量导入数据
查看>>
pandas 修改指定列中所有内容
查看>>
「 Luogu P2285 」打鼹鼠
查看>>
lua语言入门之Sublime Text设置lua的Build System
查看>>
vue.js基础
查看>>
电脑的自带图标的显示
查看>>
[转载] redis 的两种持久化方式及原理
查看>>
C++ 删除字符串的两种实现方式
查看>>
ORA-01502: 索引'P_ABCD.PK_WEB_BASE'或这类索引的分区处于不可用状态
查看>>