省选模拟赛 LYK loves graph(graph)
题目描述
LYK喜欢花花绿绿的图片,有一天它得到了一张彩色图片,这张图片可以看做是一张n*m的网格图,每个格子都有一种颜色去染着,我们用-1至n*m-1来表示一个格子的颜色。特别地,-1代表这个颜色是黑色,LYK不喜欢黑色!
LYK想将剪下这张图片中的一张子图片来(四联通块),使得这个子图片不存在黑色的格子,并且至少有k个不同的颜色。
但是每个格子有自己的脾气,特别的,第i行第j列这个格子如果被LYK选中了,LYK需要花费相应的代价。LYK想花费尽可能少的代价来剪下一张满足自己要求的图片。
输入格式(graph.in)
第一行三个整数,n,m,k.
接下来n行,每行m个数,表示图片中每个格子的颜色,每个数在-1到n*m-1之间。
接下来n行,每行m个数,表示选择每个位置所需要的代价。
输出格式(graph.out)
一行,表示最小代价和。
输入样例
3 3 3
0 0 1
2 3 3
-1 2 1
3 1 5
4 10 1
9 3 4
输出样例
7
数据范围
对于20%的数据:1<=n,m,k<=4。
对于另外30%的数据:不同的颜色数<=10(不包括-1)。
对于再另外30%的数据:1<=n<=2,1<=m<=15。
对于100%的数据:1<=n,m<=15,1<=k<=7,1<=ai,j<=100000。
数据保证一定有解。
分析:对于前50%的数据,就是一个裸的斯坦纳树. 剩下50%的数据因为颜色数太多,状态表示不下.
注意到k 还是≤7,也就是我们只关注7个不同的颜色. 利用概率性算法,将所有的颜色随机映射到k种颜色中,然后利用前50%的数据的算法. 做一次的成功率是非常低的,多做几次就好了.
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int inf = 0x7ffffff;
const int dx[] = {,,,-},dy[] = {,-,,}; int n,m,k,ans = inf,tot,maxx,block,who,maxn;
int col[][],a[][],flag[][];
int vis[],bb[],f[][][],g[],vis2[][];
bool can[][];
int b[],cnt,Time = ,pos[]; struct node
{
int x,y;
}; void spfa(int sta)
{
queue <node> q;
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
if (col[i][j] != -)
{
node temp;
temp.x = i;
temp.y = j;
q.push(temp);
vis2[i][j] = ;
}
}
while (!q.empty())
{
node u = q.front();
q.pop();
int x = u.x,y = u.y;
vis2[x][y] = ;
for (int i = ; i < ; i++)
{
int nx = x + dx[i],ny = y + dy[i];
if (nx >= && nx <= n && ny >= && ny <= m && col[nx][ny] != -)
{
if (f[nx][ny][sta] > f[x][y][sta] + a[nx][ny])
{
f[nx][ny][sta] = f[x][y][sta] + a[nx][ny];
if (!vis2[nx][ny])
{
vis2[nx][ny] = ;
node temp;
temp.x = nx;
temp.y = ny;
q.push(temp);
}
}
}
}
}
} bool check2(int x)
{
int res = ;
while (x)
{
if (x & )
res++;
x >>= ;
}
if (res >= k)
return true;
return false;
} void solve2()
{
tot = ;
memset(vis,,sizeof(vis));
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
if (col[i][j] != -)
{
if (!vis[col[i][j]])
{
bb[col[i][j]] = ++tot;
vis[col[i][j]] = ;
}
}
}
maxx = ( << tot) - ;
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
for (int k = ; k <= maxx; k++)
f[i][j][k] = inf;
for (int k = ; k <= maxx; k++)
g[k] = inf;
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
if (col[i][j] != -)
f[i][j][ << (bb[col[i][j]] - )] = a[i][j];
}
for (int i = ; i <= maxx; i++)
{
for (int j = ; j <= n; j++)
for (int k = ; k <= m; k++)
for (int l = i; l; l = (l - ) & i)
f[j][k][i] = min(f[j][k][i],f[j][k][l] + f[j][k][l ^ i] - a[j][k]);
spfa(i);
for (int j = ; j <= n; j++)
for (int k = ; k <= m; k++)
g[i] = min(g[i],f[j][k][i]);
}
for (int i = ; i <= maxx; i++)
if (check2(i))
ans = min(ans,g[i]);
printf("%d\n",ans);
} void spfa2(int sta)
{
memset(vis2,,sizeof(vis2));
queue <node> q;
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
if (col[i][j] != -)
{
node temp;
temp.x = i;
temp.y = j;
q.push(temp);
vis2[i][j] = ;
}
}
while (!q.empty())
{
node u = q.front();
q.pop();
int x = u.x,y = u.y;
vis2[x][y] = ;
for (int i = ; i < ; i++)
{
int nx = x + dx[i],ny = y + dy[i];
if (nx >= && nx <= n && ny >= && ny <= m && col[nx][ny] != -)
{
if (f[nx][ny][sta] > f[x][y][sta] + a[nx][ny])
{
f[nx][ny][sta] = f[x][y][sta] + a[nx][ny];
if (!vis2[nx][ny])
{
vis2[nx][ny] = ;
node temp;
temp.x = nx;
temp.y = ny;
q.push(temp);
}
}
}
}
}
} void solve()
{
maxx = ( << ) - ;
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
for (int k = ; k <= maxx; k++)
f[i][j][k] = inf;
for (int k = ; k <= maxx; k++)
g[k] = inf;
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
if (col[i][j] != -)
f[i][j][ << (pos[col[i][j]] - )] = a[i][j];
}
for (int i = ; i <= maxx; i++)
{
for (int j = ; j <= n; j++)
for (int k = ; k <= m; k++)
for (int l = i; l; l = (l - ) & i)
f[j][k][i] = min(f[j][k][i],f[j][k][l] + f[j][k][l ^ i] - a[j][k]);
spfa2(i);
for (int j = ; j <= n; j++)
for (int k = ; k <= m; k++)
g[i] = min(g[i],f[j][k][i]);
}
for (int i = ; i <= maxx; i++)
{
if (check2(i))
ans = min(ans,g[i]);
}
} int main()
{ scanf("%d%d%d",&n,&m,&k);
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
{
scanf("%d",&col[i][j]);
if (col[i][j] != -)
b[++cnt] = col[i][j];
}
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
scanf("%d",&a[i][j]);
sort(b + ,b + + cnt);
cnt = unique(b + ,b + + cnt) - b - ;
if (cnt <= )
solve2();
else
{
Time = ;
while (Time--)
{
random_shuffle(b + ,b + + cnt);
for (int i = ; i <= cnt; i++)
pos[b[i]] = ((i - ) % ) + ;
solve();
}
printf(" %d\n",ans);
} return ;
}
省选模拟赛 LYK loves graph(graph)的更多相关文章
- 省选模拟赛 LYK loves rabbits(rabbits)
题目描述 LYK喜欢兔子,它在家中养了3只兔子. 有一天,兔子不堪寂寞玩起了游戏,3只兔子排成一排,分别站在a,b,c这3个位置. 游戏的规则是这样的,重复以下步骤k次:选择两个不同的兔子A和B,假如 ...
- 省选模拟赛 LYK loves string(string)
题目描述 LYK喜欢字符串,它认为一个长度为n的字符串一定会有n*(n+1)/2个子串,但是这些子串是不一定全部都不同的,也就是说,不相同的子串可能没有那么多个.LYK认为,两个字符串不同当且仅当它们 ...
- 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解
今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...
- @省选模拟赛03/16 - T3@ 超级树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...
- 3.28 省选模拟赛 染色 LCT+线段树
发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...
- NOI2016模拟赛Zbox loves stack
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- [noi.ac省选模拟赛]第12场题解集合
题目 比赛界面. T1 数据范围明示直接\(O(n^2)\)计算,问题就在如何快速计算. 树上路径统计通常会用到差分方法.这里有两棵树,因此我们可以做"差分套差分",在 A 树上对 ...
- [noi.ac省选模拟赛]第11场题解集合
题目 比赛界面. T1 比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配. 尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...
- 省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)
一 稍微转化一下,就是找所有和原树差距不超过k的不同构树的个数 一个挺trick的想法是: 由于矩阵树定理的行列式的值是把邻接矩阵数值看做边权的图的所有生成树的边权乘积之和 那么如果把不存在于原树中的 ...
随机推荐
- 使用performance进行前端性能监控
该文章仅作为自己的总结 1.performance.timing对象 navigationStart:当前浏览器窗口的前一个网页关闭,发生unload事件时的Unix毫秒时间戳.如果没有前一个网页,则 ...
- 关于XSS的一些知识点
安全套接层(SSL)无助于减少XSS攻击.当Web浏览器使用SSL的时候,在网络中传送的数据是经过加密的,但是因为XSS攻击是在客户机器上发生的,所以数据已经被解密了,这时,攻击者仍然能够利用XSS安 ...
- 搭建Git工作环境
为什么要做版本控制? 在平时的工作中,经常会遇到写文档的事情,而写文档基本都不会一蹴而就,总是会修修改改很多次,而版本控制能够记录每次修改的版本,能够进行回溯.有很多版本控制工具,但是作为一个程序员, ...
- baidu网盘下载神器 Pandownload
最近百度网盘超级会员到期,经同学的推荐,我最近发现了一个特别NB的工具pandownload,官方说是能够破解加速,经过使用确实能够达到很快的下载速度. 这里附上官方的下载网站 http://pand ...
- UVA 10328 - Coin Toss dp+大数
题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...
- oracle执行完shutdown immediate后登陆不上了怎么办
在sqlplus 里登录后使用shutdown immediate 关闭数据库后若没有使用startup重启数据库就退出窗口则会出现下一次重启sqlplus窗口时无法登录的现象,解决方法如下 一.启动 ...
- lintcode-507-摆动排序 II
507-摆动排序 II 给你一个数组nums,将它重排列如下形式 nums[0] < nums[1] > nums[2] < nums[3].... 注意事项 你可以认为每个输入都有 ...
- form 表单提交类型
multipart/form-data与x-www-form-urlencoded区别 multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信 ...
- 第210天:node、nvm、npm和gulp的安装和使用详解
一.node 1.什么是node? 它不是JS文件,也不是JS框架,而是Server side JavaScript runtime,当服务端的一个JS文件运行时,会被NODE拦截,在NODE中运行J ...
- bzoj3477[Usaco2014 Mar]Sabotage
题意 给出一个长为n的正整数序列(n<=1e5),要求选出一个非空前缀和一个非空后缀(这两段不能够加起来组成整个序列),使得这个前缀和后缀中的所有数字一起求平均数的结果最小 分析 最大/最小化平 ...