• Fire Net(HDU-1045)(匈牙利最大匹配)(建图方式)


    题意

    有一个 n*n 的图,. 代表空白区域,X 代表墙,现在要在空白区域放置结点,要求同一行同一列只能放一个,除非有墙阻隔,问最多能放多少个点

    思路

    只有在墙的阻隔情况下,才会出现一行/列出现多个点的情况,那么可以考虑进行缩点,将同一行且没有墙体阻隔的区域缩成一个点,放到左点集中,将同一列且没有墙体阻隔的区域缩成一个点,放到右点集中,从而建成一个二分图

     

    假设 i 为行编号,j 为列编号,若 i-j 之间存在一条边,就相当于在方格 (i,j) 上放了一个点,这个假设使得在没有墙体阻隔的情况下,i 行 j 列不能再放其他的点,那么在不考虑 不能同行同列 的情况下,将所有边连接起来,即行列缩点后,对应方格编号连边 

    建好图后,在图上求最大匹配即可

    C++代码一

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<utility>
    #include<stack>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    #define PI acos(-1.0)
    #define E 1e-9
    #define INF 0x3f3f3f3f
    #define LL long long
    const int MOD=1E9+7;
    const int N=1000+5;
    const int dx[]={-1,1,0,0};
    const int dy[]={0,0,-1,1};
    using namespace std;
    int n;//n行n列
    bool vis[N];//vis[i]表示是否在交替路中
    int link[N];//存储连接点
    int G[N][N];//存边
    char str[N][N];
    int x[N][N],cntX;//行点集
    int y[N][N],cntY;//列点集
    bool dfs(int x){
        for(int y=0;y<cntY;y++){//对x的每个邻接点
            if(G[x][y]==1&&!vis[y]){//不在交替路中
                vis[y]=true;//放入交替路
                if(link[y]==-1 || dfs(link[y])){//如果是未匹配点,说明交替路是增广路
                    link[y]=x;//交换路径
                    return true;//返回成功
                }
            }
        }
        return false;//不存在增广路,返回失败
    }
    int hungarian(){
        int ans=0;//记录最大匹配数
        memset(link,-1,sizeof(link));
        for(int i=0;i<cntX;i++){//从左侧开始每个结点找一次增广路
            memset(vis,false,sizeof(vis));
            if(dfs(i))//找到一条增广路,形成一个新匹配
                ans++;
        }
        return ans;
    }
    int main(){
     
        while(scanf("%d",&n)!=EOF&&n){
            memset(x,0,sizeof(x));
            memset(y,0,sizeof(y));
            memset(G,false,sizeof(G));
     
            for(int i=0;i<n;i++)
                scanf("%s",str[i]);
     
            //对行缩点
            cntX=1;
            for(int i=0;i<n;i++){//第i行
                for(int j=0;j<n;j++){//第j列
                    if(str[i][j]=='.')//同一区域
                        x[i][j]=cntX;
                    if(str[i][j]=='X')//墙体阻隔
                        cntX++;
                }
                cntX++;//下一行
            }
     
            //对列缩点
            cntY=1;
            for(int j=0;j<n;j++){//第j列
                for(int i=0;i<n;i++){//第i行
                    if(str[i][j]=='.')//同一区域
                        y[i][j]=cntY;
                    if(str[i][j]=='X')//墙体阻隔
                        cntY++;
                }
                cntY++;//下一列
            }
     
            //连边
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                    if(str[i][j]=='.')
                        G[x[i][j]][y[i][j]]=true;
     
            printf("%d
    ",hungarian());
        }
        return 0;
    }
    View Code

    C++代码二

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    struct node
    {
        int a = 0 , b = 0;
    };
    node id[6][6];
    char mp[6][6];
    bool link[105][105];
    bool vis[105];
    int use[105];
    int hcnt,rcnt;
    
    void dfsh(int x,int y){
        if(y <= n && mp[x][y] == '.'){
            id[x][y].a = hcnt;
            dfsh(x,y+1);
        }
    }
    
    void dfsr(int x,int y){
        if(x <= n && mp[x][y] == '.'){
            id[x][y].b = rcnt;
            dfsr(x+1,y);
        }
    }
    
    int find(int x)
    {
        for (int s = 1; s < rcnt; s++) {
            if (link[x][s] && !vis[s]) {
                vis[s] = 1;
                if (use[s] == 0 || find(use[s])) {
                    use[s] = x;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main(int argc, char const *argv[])
    {
        while(cin >> n && n){
            for(int i = 1;i <= n ;i ++){
                cin >> mp[i] + 1;
            }
    
                memset(id,0,sizeof id);
                memset(link,0,sizeof link);
                memset(use,0,sizeof use);
                hcnt = rcnt = 1;
                for(int i = 1;i <= n;i ++){
                    for(int j = 1;j <= n ;j ++){
                        if(mp[i][j] == 'X'){
                            continue;
                        }
                        if(id[i][j].a == 0){
                            dfsh(i,j);
                            hcnt ++;
                        }
                        if(id[i][j].b == 0){
                            dfsr(i,j);
                            rcnt ++;
                        }
                        link[id[i][j].a][id[i][j].b] = 1;
                    }
                }
                int sum = 0;
                for(int i = 1;i < hcnt;i ++){
                    memset(vis,0,sizeof vis);
                    if(find(i)) sum ++;
                }
                printf("%d
    ",sum );
            }
    
        
        return 0;
    }
    View Code

    C++代码三

    #define N 6
    #include<queue>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    char k[N][N];
    int book[N][N];
    int n,ma;
    void dfs(int step)
    {
        if(step>ma)//保留每次能放得最大碉堡数
        {
            ma=step;
            return;
        }
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                if(k[i][j]=='.'&&!book[i][j])//如果这个位置可以放碉堡
                {
                    int a=i,b=i,c=j,d=j;
                    //向四个方向覆盖,遇到边界或墙停止
                    while(a>=0&&k[a][j]=='.'){book[a][j]++;a--;}
                    while(b<n&&k[b][j]=='.'){book[b][j]++;b++;}
                    while(c>=0&&k[i][c]=='.'){book[i][c]++;c--;}
                    while(d<n&&k[i][d]=='.'){book[i][d]++;d++;}
                    dfs(step+1);//放置的碉堡数加1
                    a=i,b=i,c=j,d=j;
                    //取消覆盖
                    while(a>=0&&k[a][j]=='.'){book[a][j]--;a--;}
                    while(b<n&&k[b][j]=='.'){book[b][j]--;b++;}
                    while(c>=0&&k[i][c]=='.'){book[i][c]--;c--;}
                    while(d<n&&k[i][d]=='.'){book[i][d]--;d++;}
                }
            }
        }
        return;
    }
    int main()
    {
        while(scanf("%d",&n)&&n)
        {
            for(int i=0; i<n; i++)
                scanf("%s",k[i]);
            memset(book,0,sizeof(book));
            ma=0;
            dfs(0);
            printf("%d
    ",ma);
        }
        return 0;
    }
     
    DFS
  • 相关阅读:
    vue中创建全局单文件组件/命令
    export default与export的区别
    Android Fragment的使用(转载)
    ios 内存管理总结
    object-c 混编 调用C,C++接口
    Python3基础 yield send 获得生成器后,需要先启动一次
    Python3基础 yield next 获取生成器生出的值
    Python3基础 函数 无return、return 空或None 的效果相同
    Python3基础 函数 函数名赋值操作
    Python3基础 函数 函数名作为参数传给函数
  • 原文地址:https://www.cnblogs.com/DWVictor/p/11348382.html
Copyright © 2020-2023  润新知