省选模拟赛 LYK loves graph(graph)

题目描述

LYK喜欢花花绿绿的图片,有一天它得到了一张彩色图片,这张图片可以看做是一张n*m的网格图,每个格子都有一种颜色去染着,我们用-1n*m-1来表示一个格子的颜色。特别地,-1代表这个颜色是黑色,LYK不喜欢黑色!

LYK想将剪下这张图片中的一张子图片来(四联通块),使得这个子图片不存在黑色的格子,并且至少有k个不同的颜色。 

但是每个格子有自己的脾气,特别的,第i行第j列这个格子如果被LYK选中了,LYK需要花费相应的代价。LYK想花费尽可能少的代价来剪下一张满足自己要求的图片。

输入格式(graph.in)

    第一行三个整数,n,m,k.

    接下来n行,每行m个数,表示图片中每个格子的颜色,每个数在-1n*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<=21<=m<=15

对于100%的数据:1<=n,m<=151<=k<=71<=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\n",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\n",ans);
    }

    return 0;
}

 

posted @ 2018-03-25 23:33  zbtrs  阅读(334)  评论(0编辑  收藏  举报