zoukankan      html  css  js  c++  java
  • 灯泡游戏 (Kruskal)(并查集)

    灯泡游戏

    时间限制: 1 Sec  内存限制: 64 MB
    提交: 9  解决: 4
    [提交][状态][讨论版]

    题目描述

    有 一个n行m列的矩阵,左上角坐标是(0,0),右下角坐标是(n-1,m-1)。每个格子有一个字符, “0”至“9”表示数字0至9,“a”至“z”表示数字10至35,“A”至“Z”表示数字36至61。矩阵的每个格子都有一个灯泡,刚开始除了左上角的 灯泡是亮的,其他的灯泡都是灭的,刚开始你的得分是0。
    游戏的过程是这样的:每次选一个灯泡是亮的格子X,同时选一个灯泡是灭的格子Y,而且要求 格子X和格子Y是相邻的格子。这个步骤会使你的得分增加,增加的值是:格子X与格子Y代表的数字的差的绝对值。当然,这个步骤会使你选中的灭的灯泡变亮。 重复上述操作,直到所有的灯泡都变成亮的。问你的最大得分是多少?

    输入

    第1行:两个整数n和m(1≤n,m≤50)。
      接下来是n行m列的矩阵。
      

    输出

      一个整数,表示最大得分。

    样例输入

    2  2
    05
    aB
    

    样例输出

    69
    

    提示

    第一次选择:格子(0,0)和格子(1,0),得分是10-0=10;第二次选择:格子(1,0)和格子(1,1),得分是37-10:27;第三次选择:格子(1,1)和格子(0,1),得分是37-5=32,因此总得分是:10+27+32=69。

    【分析】又学到了一种算法,求最小生成树的,当然这题是最大生成树,我用的是Kruskal算法,下面是AC代码。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <cstring>
    #include <string>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <list>
    #define mod 1000000007
    #define inf 0x3f3f3f3f
    #define pi acos(-1.0)
    using namespace std;
    typedef long long ll;
    const int N=2859;
    int n,m,k,cnt=-1;
    int d[4][2]= {0,1,1,0,0,-1,-1,0};
    int parent[N+60];
    bool vis[N][N];
    char mp[55][55];
    struct man {
        int u,v,w;
    } edg[N];//结构体存节点与节点之间的权值
    bool cmp(man g,man h) {
        return g.w>h.w;
    }//将权值即得分从大到小排序
    int change(char ch) {
        if(ch>='0'&&ch<='9')return (ch-'0');
        else if(ch>='a'&&ch<='z')return (ch-87);
        else return (ch-29);
    }//字符转为数字
    void init() {
        for(int i=0; i<=2855; i++)parent[i]=i;
    }//初始化
    int Find(int x) {
        if(parent[x] != x) parent[x] = Find(parent[x]);
        return parent[x];
    }//查找并返回节点x所属集合的根节点
    void Union(int x,int y) {
        x = Find(x);
        y = Find(y);
        if(x == y) return;
        parent[y] = x;
    }//将两个不同集合的元素进行合并
    void Build()//将矩形图转化为树
    {
        for(int i=0; i<n; i++) {
            for(int j=0; j<m; j++) {
                for(int k=0; k<4; k++) {
                    int xx=i+d[k][0],yy=j+d[k][1];
                    if(xx>=0&&xx<n&&yy>=0&&yy<m) {
                        int I=i*55+j,J=xx*55+yy;
                        if(!vis[I][J]) {
                            edg[++cnt].u=I;
                            edg[cnt].v=J;
                            edg[cnt].w=abs(change(mp[i][j])-change(mp[xx][yy]));
                            vis[I][J]=true;
                        }
                    }
                }
            }
        }
    }
    void Kruskal() {
        int sumweight=0;//生成树的总权值,即所得分数
        int num=0;//已经选用边的数目
        int u,v;//顶点
        init();
        for(int i=0; i<=cnt; i++) {
            u=edg[i].u;
            v=edg[i].v;
            if(Find(u)!=Find(v)) {
                sumweight+=edg[i].w;
                num++;
                Union(u,v);
            }
            if(num>=n*m-1) break;//边已经全部建好
        }
        printf("%d
    ",sumweight);
    }
    int main() {
        memset(vis,false,sizeof(vis));
        int u,v,w;
        cin>>n>>m;
        for(int i=0; i<n; i++)cin>>mp[i];
        Build();
        sort(edg,edg+cnt+1,cmp);
        Kruskal();
        return 0;
    }
    View Code
  • 相关阅读:
    Windows下好用的git客户端--GitExtentions
    高分辨率下放大netbeans中的小图标
    小书匠使用手册
    win8 telnet VirtualBox中的redhat9
    win8安装新字体
    netbeans设置字体
    win7下Chrome有两个图标的解决方法
    【转】HDU-6035-Colorful Tree
    POJ1703--Find them, Catch them(种类并查集)
    KMP的妙用(利用next数组寻找字符串的循环节)
  • 原文地址:https://www.cnblogs.com/jianrenfang/p/5725205.html
Copyright © 2011-2022 走看看