【THUSC2017】【LOJ2977】巧克力 斯坦纳树
题目大意
有一个网格(或者你可以认为这是一个图),每个点都有颜色 \(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】巧克力 斯坦纳树的更多相关文章
- loj2977 巧克力 (斯坦纳树+随机化)
考虑颜色比较少的时候,第一问可以直接斯坦纳树 第二问考虑二分,每次把每格的权值给成1000+[a[i]>m],就是在个数最少的基础上尽量选小于等于m的 然而颜色太多不能直接做,但可以把每种颜色映 ...
- [THUSC2017]巧克力[斯坦纳树、随机化]
题意 题目链接 分析 对于第一问,如果颜色数量比较少的话可以 \(\binom{cnt}{k}\) 枚举最终连通块中的 \(k\) 种颜色,然后利用斯坦纳树求解. 如果颜色比较多,考虑将所有的颜色重新 ...
- LOJ#2977. 「THUSCH 2017」巧克力(斯坦纳树+随机化)
题目 题目 做法 考虑部分数据(颜色较少)的: 二分中位数\(mid\),将\(v[i]=1000+(v[i]>mid)\) 具体二分操作:然后求出包含\(K\)种颜色的联通快最小的权值和,判断 ...
- LOJ 2997 「THUSCH 2017」巧克力——思路+随机化+斯坦纳树
题目:https://loj.ac/problem/2977 想到斯坦纳树.但以为只能做 “包含一些点” 而不是 “包含一些颜色” .而且不太会处理中位数. 其实 “包含一些颜色” 用斯坦纳树做也和普 ...
- 洛谷 P7450 - [THUSCH2017] 巧克力(斯坦纳树+随机化)
洛谷题面传送门 9.13 补之前 8.23 做的题,不愧是鸽子 tzc( 首先我们先来探讨一下如果 \(c_{i,j}\le k\) 怎么做,先考虑第一问.显然一个连通块符合条件当且仅当它能够包含所有 ...
- 【BZOJ2595】游览计划(状压DP,斯坦纳树)
题意:见题面(我发现自己真是越来越懒了) 有N*M的矩阵,每个格子有一个值a[i,j] 现要求将其中的K个点(称为关键点)用格子连接起来,取(i,j)的费用就是a[i,j] 求K点全部连通的最小花费以 ...
- HDU 4085 斯坦纳树
题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整 ...
- 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 ...
- hdu 3311 斯坦纳树
思路:虚拟一个0号节点,将每个点建一条到0号节点的边,权值为挖井需要的价值.并要保证0号节点同另外n个寺庙一样被选择即可. 然后就是求斯坦纳树了. #include<map> #inclu ...
随机推荐
- leetcode math类型题目解题总结
2. Add Two Numbers https://leetcode.com/problems/add-two-numbers/description/ class Solution { publi ...
- KOA中间件的基本运作原理
示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址:[你要的前端打怪升级指南] 在中 ...
- Neo4j入门之中国电影票房排行浅析
什么是Neo4j? Neo4j是一个高性能的NoSQL图形数据库(Graph Database),它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持 ...
- js对象数组(JSON) 根据某个共同字段 分组
首先判断 var arr = [ {"id":"1001","name":"值1","value": ...
- 设计模式 - 单例模式(Singleton Pattern)
单例模式 介绍 模式:创建型 意图:保证一个类只有一个实例,并提供一个访问它的全局访问点 解决:一个全局使用的类频繁地创建与销毁 场景: 唯一序列号 web中的计数器 I/O与数据库的连接 …… 实现 ...
- Django之无名分组,有名分组
在Django 2.0版本之前,在urls,py文件中,用url设定视图函数 urlpatterns = [ url(r'login/',views.login), ] 其中第一个参数是正则匹配,如下 ...
- 【设计模式】适配器模式 Adapter Pattern
适配器模式在软件开发界使用及其广泛,在工业界,现实中也是屡见不鲜.比如手机充电器,笔记本充电器,广播接收器,电视接收器等等.都是适配器. 适配器主要作用是让本来不兼容的两个事物兼容和谐的一起工作.比如 ...
- .NET Core 学习笔记2——管理nuget包
.NET Core 基于Nuget包.它是一个.nupkg后缀的zip文件. 工具 dotnet 工具 vs2017 的程序包管理控台 这两个工具都可以用命令行来下载安装,更新,上传包(上传要先在网站 ...
- Jmeter Beanshell 用法
Beanshell 的用法 什么是beanshell Beanshell是一种完全符合java语法的脚本语言,并且拥有自己的内置对象和语法 Beanshell是用java写的,一个小型嵌入式java源 ...
- Centos7 二进制安装 Kubernetes 1.13
目录 1.目录 1.1.什么是 Kubernetes? 1.2.Kubernetes 有哪些优势? 2.环境准备 2.1.网络配置 2.2.更改 HOSTNAME 2.3.配置ssh免密码登录登录 2 ...