zoukankan      html  css  js  c++  java
  • POJ

    *.*.
    .***
    ***.
    ..*.

    题意:有一个N*M的像素图,现在问最少能用几块1*k的木条覆盖所有的 * 点,k为>=1的任意值。

    分析:和小行星那题很像。小行星那题是将一整行(列)看作一个点,但本题一行或一列内可能有多个连通块。所以先根据像素图统计出总的行列连通块的个数。

    将行连通块视作X部;列连通块视作Y部;连接一对行列连通块的*像素点视作边,问题转化为了用最少的边去覆盖所有的点,即最小点覆盖。

    建图之后求二分图的最小点覆盖。

    #include<iostream>
    #include<cstring>
    #include<stdio.h>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const int maxn = 1300;
    int N;
    struct Edge{
        LL val;
        int to,next;
    }edges[maxn<<2];
    int head[maxn],tot;
    int linker[maxn];
    bool used[maxn];
    
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
    }
    
    void AddEdge(int u,int v, LL val)
    {
        edges[tot].val = val;
        edges[tot].to = v;
        edges[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool dfs(int u){
        int v;
        for(int i=head[u];~i;i = edges[i].next){
            v = edges[i].to;
            if(!used[v]){
                used[v]=true;
                if(linker[v]==-1||dfs(linker[v])){
                    linker[v]=u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int hungary(){
        int u;
        int res=0;
        memset(linker,-1,sizeof(linker));
        for(u=1;u<=N;u++){
            memset(used,0,sizeof(used));
            if(dfs(u)) res++;
        }
        return res; 
    }
    
    int idx[60][60],idy[60][60];
    char G[maxn][maxn];
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int M;
        while(scanf("%d%d",&N,&M)==2){
            init();
            for(int i=1;i<=N;++i){
                scanf("%s",G[i]+1);
            }
            memset(idx,0,sizeof(idx));
            memset(idy,0,sizeof(idy));
            int cnt1=0,cnt2 = 0;
            for(int i=1;i<=N;++i){
                for(int j=1;j<=M;++j){
                    if(G[i][j]!='*') continue;
                    if(idx[i][j-1]) idx[i][j] = idx[i][j-1];
                    else idx[i][j] = ++cnt1;
                    if(idy[i-1][j]) idy[i][j] = idy[i-1][j];
                    else idy[i][j] = ++cnt2;
                }
            }
            for(int i=1;i<=N;++i){
                for(int j=1;j<=M;++j){
                    if(G[i][j]=='*')
                        AddEdge(idx[i][j],idy[i][j],0);
                }
            }
            N = cnt1;
            printf("%d
    ",hungary());
        }
        return 0;
    }
    
    
    为了更好的明天
  • 相关阅读:
    java降序排列
    冒泡排序-java
    redis-并发竞争问题
    超卖问题
    算法-题目汇总-6
    算法-题目汇总-4
    算法-题目汇总-1
    算法-二分查找-1
    算法-bst-平衡搜索二叉树-1
    算法-位运算-1
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9508161.html
Copyright © 2011-2022 走看看