zoukankan      html  css  js  c++  java
  • 省选模拟赛 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
    ",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;
    }
  • 相关阅读:
    nginx主配置文件详解
    微信网页第三方登录原理
    QQ第三方登陆流程详解
    php垃圾回收机制
    mysql索引
    MySQL性能优化的最佳20+条经验
    MYSQL explain详解
    mysql分区功能详细介绍,以及实例
    MySQL分表、分区
    Redis主从读写分离配置
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8647784.html
Copyright © 2011-2022 走看看