zoukankan      html  css  js  c++  java
  • hdu4185+poj3020(最大匹配+最小边覆盖)

    传送门:hdu4185 Oil Skimming

    题意:n*n的方格里有字符*和#,只能在字符#上放1*2的板子且不能相交,求最多能放多少个。

    分析:直接给#字符编号,然后相邻的可以匹配,建边后无向图跑匈牙利算法,最后得到的最大匹配数/2。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstdlib>
    #include <stack>
    #include <vector>
    #include <set>
    #include <map>
    #define LL long long
    #define mod 100000000
    #define inf 0x3f3f3f3f
    #define eps 1e-6
    #define N 610
    #define FILL(a,b) (memset(a,b,sizeof(a)))
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define PII pair<int,int>
    using namespace std;
    int match[N],vis[N],n,m,cnt;
    int g[N][N],mat[N][N];
    char s[N][N];
    int dfs(int u)
    {
        for(int i=1;i<=cnt;i++)
        {
            if(!vis[i]&&g[u][i])
            {
                vis[i]=1;
                if(match[i]==-1||dfs(match[i]))
                {
                    match[i]=u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int hungary()
    {
        memset(match,-1,sizeof(match));
        int ans=0;
        for(int i=1;i<=cnt;i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i))ans++;
        }
        return ans;
    }
    void judge(int i,int j)
    {
        if(j+1<=n&&mat[i][j+1])
            g[mat[i][j]][mat[i][j+1]]=g[mat[i][j+1]][mat[i][j]]=1;
        if(i+1<=n&&mat[i+1][j])
            g[mat[i][j]][mat[i+1][j]]=g[mat[i+1][j]][mat[i][j]]=1;
    }
    int main()
    {
        int T,cas=1;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%s",s[i]+1);
            cnt=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                    if(s[i][j]=='#')
                    mat[i][j]=++cnt;
                    else mat[i][j]=0;
            }
            FILL(g,0);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                if(mat[i][j])judge(i,j);
            int res=hungary();
            printf("Case %d: %d
    ",cas++,res/2);
        }
    }
    View Code

    传送门: poj 3020 Antenna Placement

    题意:n*m的方格里有字符*和o,相邻的两个字符*可以连接,求覆盖完所有的*最少需要多少边。

    分析:最少边覆盖所有点,就是最少边覆盖,最少边覆盖=总结点-最大匹配(双向图)/2。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstdlib>
    #include <stack>
    #include <vector>
    #include <set>
    #include <map>
    #define LL long long
    #define mod 100000000
    #define inf 0x3f3f3f3f
    #define eps 1e-6
    #define N 410
    #define FILL(a,b) (memset(a,b,sizeof(a)))
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define PII pair<int,int>
    using namespace std;
    int match[N],vis[N],n,m,cnt;
    int g[N][N],mat[N][N];
    char s[N][N];
    int dfs(int u)
    {
        for(int i=1;i<=cnt;i++)
        {
            if(!vis[i]&&g[u][i])
            {
                vis[i]=1;
                if(match[i]==-1||dfs(match[i]))
                {
                    match[i]=u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int hungary()
    {
        memset(match,-1,sizeof(match));
        int ans=0;
        for(int i=1;i<=cnt;i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i))ans++;
        }
        return ans;
    }
    void judge(int i,int j)
    {
        if(j+1<=m&&mat[i][j+1])
            g[mat[i][j]][mat[i][j+1]]=g[mat[i][j+1]][mat[i][j]]=1;
        if(i+1<=n&&mat[i+1][j])
            g[mat[i][j]][mat[i+1][j]]=g[mat[i+1][j]][mat[i][j]]=1;
    }
    int main()
    {
        int T,cas=1;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                scanf("%s",s[i]+1);
            cnt=0;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                    if(s[i][j]=='*')
                    mat[i][j]=++cnt;
                    else mat[i][j]=0;
            }
            FILL(g,0);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                if(mat[i][j])judge(i,j);
            int res=hungary();
            printf("%d
    ",cnt-res/2);
        }
    }
    View Code
  • 相关阅读:
    SGU 176.Flow construction (有上下界的最大流)
    POJ 2391.Ombrophobic Bovines (最大流)
    poj 1087.A Plug for UNIX (最大流)
    poj 1273.PIG (最大流)
    POJ 2112.Optimal Milking (最大流)
    SGU 196.Matrix Multiplication
    SGU 195. New Year Bonus Grant
    关于multicycle path
    ppt做gif动图
    codeforces 598A Tricky Sum
  • 原文地址:https://www.cnblogs.com/lienus/p/4287110.html
Copyright © 2011-2022 走看看