zoukankan      html  css  js  c++  java
  • hdu 5093 Battle ships (二分图)

    二分图最大匹配问题

    遇到冰山就把行列拆成两个部分。每个部分x也好,y也好只能匹配一次

    图画得比较草,将就着看

     

    横着扫一遍,竖着扫一遍,得到编号

    一个位置就对应一个(xi,yi)就是X集到Y集的一条边,

    由题意,每个点只能被选择一次。所以最大匹配的边数就是答案了。

    算法过程

    当增广路不存在的时候,就是二分图最大匹配。(同样适用其他任意图,可以求最大流)

    通常都是先贪心求一个匹配,然后开始增广。

    寻找增广路的过程:

      一个没有和任意边匹配的点叫做未盖点,从左集X中一个未盖点u出发寻找增广路。

      从u出发,选一个非匹配边到达Y集中的v,如果v没匹配,那么就找到一条增广路(只要把之前走过的匹配边和非匹配边交换,匹配边数加一)。否则沿着v的匹配边回来,然后重复以上过程。

    做这题的过程中,把数组开小了导致TLE...还加了个反向边,不过在debug过程中到是发现了不用每次都memset vis数组的小技巧

    #include<cstdio>
    #include<cstring>
    
    const int maxn = 52;
    const int maxv = 2550; // 500
    const int maxe = (maxv*maxv);
    char pg[maxn][maxn];
    int g[maxn][maxn][2];
    
    int to[maxe],nxt[maxe],head[maxv],ecnt;
    int match[maxv];
    
    
    void addEdge(int u,int v)
    {
        to[ecnt] = v;
        nxt[ecnt] = head[u];
        head[u] = ecnt++;
    }
    
    int vis[maxv];
    int times;
    //find augmenting path
    bool dfs(int u)
    {
        for(int i = head[u]; ~i; i = nxt[i]){
            int v = to[i];
            if(vis[v]!= times){
                vis[v]  = times;
                if(!~match[v] || dfs(match[v]) ){
                    match[v] = u;
                    return true;
                }
            }
    
        }
        return false;
    }
    
    int x_num,y_num;
    
    void go()
    {
        memset(match,-1,sizeof(match));
        int ans = 0;
        for(int i = 0; i < x_num; i++ ){
            times++;
            if(dfs(i)) ans++;
        }
        printf("%d
    ",ans);
    }
    
    void init(){
        memset(head,-1,sizeof(head));
        ecnt = 0;
        x_num = 0;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int T;
        times = 0;
        scanf("%d",&T);
        while(T--){
            init();
            int m,n;
            scanf("%d%d",&m,&n);
            for(int i = 0; i < m; i++)
                scanf("%s",pg[i]);
            bool flag;//如果某行没有找到那么编号不应该增加
            for(int i = 0; i < m; i++){
                flag = false;
                for(int j = 0; j < n; j++){
                    if(pg[i][j] == 'o') g[i][j][0] = -1;
                    else if(pg[i][j] == '#') g[i][j][0] = -1,x_num++;
                    else g[i][j][0] =  x_num,flag = true;
                }
                if(flag) x_num++;
            }
    
            y_num = x_num;
            for(int j = 0; j < n; j++){
                flag = false;
                for(int i = 0; i < m; i++){
                     if(pg[i][j] == 'o') ;
                    else if(pg[i][j] == '#') y_num++;
                    else g[i][j][1] =  y_num,flag = true;
                }
                if(flag) y_num++;
            }
    
            for(int i = 0; i < m; i++)
                for(int j = 0; j < n; j++){
                    if(~g[i][j][0]){
                        addEdge(g[i][j][0],g[i][j][1]);
                    }
                }
            go();
        }
        return 0;
    }
  • 相关阅读:
    张艾迪(创始人):视觉计算极简主义的设计
    张艾迪(创始人):同一个世界.同一个梦想
    张艾迪(创始人):Hello.世界...
    张艾迪(创始人):理念是全世界都在用....
    张艾迪(创始人):解码互联网天才
    张艾迪(创始人):艾迪成长记
    张艾迪(创始人): 趣味励志
    张艾迪(创始人): 励志的路上
    张艾迪(创始人):创始人故事无限N个
    张艾迪(创始人): 从诞生那一刻.走向整个世界
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4655193.html
Copyright © 2011-2022 走看看