题目描述

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)的更多相关文章

  1. 省选模拟赛 LYK loves rabbits(rabbits)

    题目描述 LYK喜欢兔子,它在家中养了3只兔子. 有一天,兔子不堪寂寞玩起了游戏,3只兔子排成一排,分别站在a,b,c这3个位置. 游戏的规则是这样的,重复以下步骤k次:选择两个不同的兔子A和B,假如 ...

  2. 省选模拟赛 LYK loves string(string)

    题目描述 LYK喜欢字符串,它认为一个长度为n的字符串一定会有n*(n+1)/2个子串,但是这些子串是不一定全部都不同的,也就是说,不相同的子串可能没有那么多个.LYK认为,两个字符串不同当且仅当它们 ...

  3. 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解

    今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...

  4. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  5. 3.28 省选模拟赛 染色 LCT+线段树

    发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...

  6. NOI2016模拟赛Zbox loves stack

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  7. [noi.ac省选模拟赛]第12场题解集合

    题目 比赛界面. T1 数据范围明示直接\(O(n^2)\)计算,问题就在如何快速计算. 树上路径统计通常会用到差分方法.这里有两棵树,因此我们可以做"差分套差分",在 A 树上对 ...

  8. [noi.ac省选模拟赛]第11场题解集合

    题目   比赛界面. T1   比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配.   尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...

  9. 省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)

    一 稍微转化一下,就是找所有和原树差距不超过k的不同构树的个数 一个挺trick的想法是: 由于矩阵树定理的行列式的值是把邻接矩阵数值看做边权的图的所有生成树的边权乘积之和 那么如果把不存在于原树中的 ...

随机推荐

  1. 一学就会pip换镜像源

    首先介绍一个国内好用的镜像站 阿里云 http://mirrors.aliyun.com/pypi/simple/ 豆瓣 http://pypi.douban.com/simple/ 清华大学 htt ...

  2. 【sed】常用命令

    替换 替换某一整行 sed '1c hello' test #将第一行替换为hello str1替换为str2 sed 's/^str1.*/str2/' filename #以str1开头 sed ...

  3. 小数第n位:高精度

    小数第n位 问题描述 我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数. 如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式. 本题的任务是:在上面的约定下,求整数除法小数点后 ...

  4. 如何通俗理解贝叶斯推断与beta分布?

    有一枚硬币(不知道它是否公平),假如抛了三次,三次都是“花”: 能够说明它两面都是“花”吗? 1 贝叶斯推断 按照传统的算法,抛了三次得到三次“花”,那么“花”的概率应该是: 但是抛三次实在太少了,完 ...

  5. leetcode个人题解——#43 Multiply Strings

    思路:高精度乘法就可以了. 有两个错误以前没在意,1.成员属性定义时候不能进行初始化, vector<); 这样隐性调用了函数进行初始化的形式特别要注意,也是错误的: 2.容器类只有分配了空间时 ...

  6. visual studio 2010 和 VSS(Visual SourceSafe)的连接使用

    visual studio 2010 和 VSS(Visual SourceSafe)的连接使用 1. 在visual vstudio中选择使用VSS插件: 2.       使用VSS进行源码管理: ...

  7. 一个小时搭建一个全栈 Web 应用框架

    把想法变为现实的能力是空想家与实干家的区别.不管你是在一家跨国公司工作,还是正在为自己的创业公司而努力,那些有能力将创意转化为真正产品的人,都具有宝贵的技能并拥有明显的实力.如果你能在不到一个小时的时 ...

  8. c++ Dynamic Memory (part 1)

    1. make_shared<T>(args): return a shared_ptr dynamically allocated object of type T. Use args ...

  9. Scrum立会报告+燃尽图(Beta阶段第二周第四次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2412 项目地址:https://coding.net/u/wuyy694 ...

  10. 冲刺ing-4

    第四次Scrum冲刺 队员完成的任务 队员 完成任务 吴伟华 Leangoo的看板截图,燃尽图 蔺皓雯 编写博客,学习后端设计 蔡晨旸 学习后端设计 曾茜 后端设计 鲁婧楠 服务器建构 杨池宇 学习后 ...