题目描述
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[5] = {0,0,1,-1},dy[5] = {1,-1,0,0}; int n,m,k,ans = inf,tot,maxx,block,who,maxn; int col[20][20],a[20][20],flag[20][20]; int vis[300],bb[300],f[20][20][3010],g[3010],vis2[20][20]; bool can[20][20]; int b[400],cnt,Time = 380,pos[400]; struct node { int x,y; }; void spfa(int sta) { queue <node> q; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (col[i][j] != -1) { node temp; temp.x = i; temp.y = j; q.push(temp); vis2[i][j] = 1; } } while (!q.empty()) { node u = q.front(); q.pop(); int x = u.x,y = u.y; vis2[x][y] = 0; for (int i = 0; i < 4; i++) { int nx = x + dx[i],ny = y + dy[i]; if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && col[nx][ny] != -1) { 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] = 1; node temp; temp.x = nx; temp.y = ny; q.push(temp); } } } } } } bool check2(int x) { int res = 0; while (x) { if (x & 1) res++; x >>= 1; } if (res >= k) return true; return false; } void solve2() { tot = 0; memset(vis,0,sizeof(vis)); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (col[i][j] != -1) { if (!vis[col[i][j]]) { bb[col[i][j]] = ++tot; vis[col[i][j]] = 1; } } } maxx = (1 << tot) - 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int k = 0; k <= maxx; k++) f[i][j][k] = inf; for (int k = 0; k <= maxx; k++) g[k] = inf; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (col[i][j] != -1) f[i][j][1 << (bb[col[i][j]] - 1)] = a[i][j]; } for (int i = 0; i <= maxx; i++) { for (int j = 1; j <= n; j++) for (int k = 1; k <= m; k++) for (int l = i; l; l = (l - 1) & 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 = 1; j <= n; j++) for (int k = 1; k <= m; k++) g[i] = min(g[i],f[j][k][i]); } for (int i = 0; i <= maxx; i++) if (check2(i)) ans = min(ans,g[i]); printf("%d ",ans); } void spfa2(int sta) { memset(vis2,0,sizeof(vis2)); queue <node> q; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (col[i][j] != -1) { node temp; temp.x = i; temp.y = j; q.push(temp); vis2[i][j] = 1; } } while (!q.empty()) { node u = q.front(); q.pop(); int x = u.x,y = u.y; vis2[x][y] = 0; for (int i = 0; i < 4; i++) { int nx = x + dx[i],ny = y + dy[i]; if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && col[nx][ny] != -1) { 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] = 1; node temp; temp.x = nx; temp.y = ny; q.push(temp); } } } } } } void solve() { maxx = (1 << 7) - 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int k = 0; k <= maxx; k++) f[i][j][k] = inf; for (int k = 0; k <= maxx; k++) g[k] = inf; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (col[i][j] != -1) f[i][j][1 << (pos[col[i][j]] - 1)] = a[i][j]; } for (int i = 0; i <= maxx; i++) { for (int j = 1; j <= n; j++) for (int k = 1; k <= m; k++) for (int l = i; l; l = (l - 1) & 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 = 1; j <= n; j++) for (int k = 1; k <= m; k++) g[i] = min(g[i],f[j][k][i]); } for (int i = 0; i <= maxx; i++) { if (check2(i)) ans = min(ans,g[i]); } } int main() { scanf("%d%d%d",&n,&m,&k); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { scanf("%d",&col[i][j]); if (col[i][j] != -1) b[++cnt] = col[i][j]; } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d",&a[i][j]); sort(b + 1,b + 1 + cnt); cnt = unique(b + 1,b + 1 + cnt) - b - 1; if (cnt <= 10) solve2(); else { Time = 300; while (Time--) { random_shuffle(b + 1,b + 1 + cnt); for (int i = 1; i <= cnt; i++) pos[b[i]] = ((i - 1) % 7) + 1; solve(); } printf(" %d ",ans); } return 0; }