题目大意

  有一个网格(或者你可以认为这是一个图),每个点都有颜色 \(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<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\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

【THUSC2017】【LOJ2977】巧克力 斯坦纳树的更多相关文章

  1. loj2977 巧克力 (斯坦纳树+随机化)

    考虑颜色比较少的时候,第一问可以直接斯坦纳树 第二问考虑二分,每次把每格的权值给成1000+[a[i]>m],就是在个数最少的基础上尽量选小于等于m的 然而颜色太多不能直接做,但可以把每种颜色映 ...

  2. [THUSC2017]巧克力[斯坦纳树、随机化]

    题意 题目链接 分析 对于第一问,如果颜色数量比较少的话可以 \(\binom{cnt}{k}\) 枚举最终连通块中的 \(k\) 种颜色,然后利用斯坦纳树求解. 如果颜色比较多,考虑将所有的颜色重新 ...

  3. LOJ#2977. 「THUSCH 2017」巧克力(斯坦纳树+随机化)

    题目 题目 做法 考虑部分数据(颜色较少)的: 二分中位数\(mid\),将\(v[i]=1000+(v[i]>mid)\) 具体二分操作:然后求出包含\(K\)种颜色的联通快最小的权值和,判断 ...

  4. LOJ 2997 「THUSCH 2017」巧克力——思路+随机化+斯坦纳树

    题目:https://loj.ac/problem/2977 想到斯坦纳树.但以为只能做 “包含一些点” 而不是 “包含一些颜色” .而且不太会处理中位数. 其实 “包含一些颜色” 用斯坦纳树做也和普 ...

  5. 洛谷 P7450 - [THUSCH2017] 巧克力(斯坦纳树+随机化)

    洛谷题面传送门 9.13 补之前 8.23 做的题,不愧是鸽子 tzc( 首先我们先来探讨一下如果 \(c_{i,j}\le k\) 怎么做,先考虑第一问.显然一个连通块符合条件当且仅当它能够包含所有 ...

  6. 【BZOJ2595】游览计划(状压DP,斯坦纳树)

    题意:见题面(我发现自己真是越来越懒了) 有N*M的矩阵,每个格子有一个值a[i,j] 现要求将其中的K个点(称为关键点)用格子连接起来,取(i,j)的费用就是a[i,j] 求K点全部连通的最小花费以 ...

  7. HDU 4085 斯坦纳树

    题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整 ...

  8. hdu4085 Peach Blossom Spring 斯坦纳树,状态dp

    (1)集合中元素表示(1<<i), i从0开始 (2)注意dp[i][ss] = min(dp[i][ss], dp[i][rr | s[i]] + dp[i][(ss ^ rr) | s ...

  9. hdu 3311 斯坦纳树

    思路:虚拟一个0号节点,将每个点建一条到0号节点的边,权值为挖井需要的价值.并要保证0号节点同另外n个寺庙一样被选择即可. 然后就是求斯坦纳树了. #include<map> #inclu ...

随机推荐

  1. leetcode math类型题目解题总结

    2. Add Two Numbers https://leetcode.com/problems/add-two-numbers/description/ class Solution { publi ...

  2. KOA中间件的基本运作原理

    示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址:[你要的前端打怪升级指南] 在中 ...

  3. Neo4j入门之中国电影票房排行浅析

    什么是Neo4j?   Neo4j是一个高性能的NoSQL图形数据库(Graph Database),它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持 ...

  4. js对象数组(JSON) 根据某个共同字段 分组

    首先判断 var arr = [ {"id":"1001","name":"值1","value": ...

  5. 设计模式 - 单例模式(Singleton Pattern)

    单例模式 介绍 模式:创建型 意图:保证一个类只有一个实例,并提供一个访问它的全局访问点 解决:一个全局使用的类频繁地创建与销毁 场景: 唯一序列号 web中的计数器 I/O与数据库的连接 …… 实现 ...

  6. Django之无名分组,有名分组

    在Django 2.0版本之前,在urls,py文件中,用url设定视图函数 urlpatterns = [ url(r'login/',views.login), ] 其中第一个参数是正则匹配,如下 ...

  7. 【设计模式】适配器模式 Adapter Pattern

    适配器模式在软件开发界使用及其广泛,在工业界,现实中也是屡见不鲜.比如手机充电器,笔记本充电器,广播接收器,电视接收器等等.都是适配器. 适配器主要作用是让本来不兼容的两个事物兼容和谐的一起工作.比如 ...

  8. .NET Core 学习笔记2——管理nuget包

    .NET Core 基于Nuget包.它是一个.nupkg后缀的zip文件. 工具 dotnet 工具 vs2017 的程序包管理控台 这两个工具都可以用命令行来下载安装,更新,上传包(上传要先在网站 ...

  9. Jmeter Beanshell 用法

    Beanshell 的用法 什么是beanshell Beanshell是一种完全符合java语法的脚本语言,并且拥有自己的内置对象和语法 Beanshell是用java写的,一个小型嵌入式java源 ...

  10. Centos7 二进制安装 Kubernetes 1.13

    目录 1.目录 1.1.什么是 Kubernetes? 1.2.Kubernetes 有哪些优势? 2.环境准备 2.1.网络配置 2.2.更改 HOSTNAME 2.3.配置ssh免密码登录登录 2 ...