hdoj 5093 Battle ships 【二分图最大匹配】

题目:hdoj 5093 Battle ships

题意:给你一个n*m的图,图中有冰山 ‘# ’,浮冰 ‘o’ 以及普通海 ‘ * ’,现在要在海中布置尽可能多的炮弹,炮弹不能突波冰山,不能让炮弹互相攻击到,问最大能不知多少个?

分析:二分图的经典题目,关键在于怎么建图,图进行两次编号,按行编号,每一行中能攻击到的一块编号成相同的数,每一列同样,然后对行和列有编号的地方进行连边,求一次最大匹配即可,我用最大流求的最大匹配。

AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define Del(a,b) memset(a,b,sizeof(a))
const int N = 1020;
const int inf = 0x3f3f3f3f;
int n,m;
int Min(int a,int b)
{
	return a>b?b:a;
}
struct Node
{
    int from,to,cap,flow;
};
vector<int> v[N];
vector<Node> e;
int vis[N];  //构建层次图
int cur[N];
void add_Node(int from,int to,int cap)
{
	Node tmp1,tmp2;
	tmp1.cap=from=from,tmp1.to=to,tmp1.cap=cap,tmp1.flow=0;
    e.push_back(tmp1);
	tmp2.from=to,tmp2.to=from,tmp2.cap=0,tmp2.flow=0;
    e.push_back(tmp2);
    int tmp=e.size();
    v[from].push_back(tmp-2);
    v[to].push_back(tmp-1);
}
bool bfs(int s,int t)
{
    Del(vis,-1);
    queue<int> q;
    q.push(s);
    vis[s] = 0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<v[x].size();i++)
        {
            Node tmp = e[v[x][i]];
            if(vis[tmp.to]<0 && tmp.cap>tmp.flow)  //第二个条件保证
            {
                vis[tmp.to]=vis[x]+1;
                q.push(tmp.to);
            }
        }
    }
    if(vis[t]>0)
        return true;
    return false;
}
int dfs(int o,int f,int t)
{
    if(o==t || f==0)  //优化
        return f;
    int a = 0,ans=0;
    for(int &i=cur[o];i<v[o].size();i++) //注意前面 ’&‘,很重要的优化
    {
        Node &tmp = e[v[o][i]];
        if(vis[tmp.to]==(vis[o]+1) && (a = dfs(tmp.to,Min(f,tmp.cap-tmp.flow),t))>0)
        {
            tmp.flow+=a;
            e[v[o][i]^1].flow-=a; //存图方式
            ans+=a;
            f-=a;
            if(f==0)  //注意优化
                break;
        }
    }
    return ans;  //优化
}

int dinci(int s,int t)
{
    int ans=0;
    while(bfs(s,t))
    {
        Del(cur,0);
        int tm=dfs(s,inf,t);
        ans+=tm;
    }
    return ans;
}
void Clear(int x)
{
    for(int i=0;i<=x;i++)
        v[i].clear();
    e.clear();
}
int row[55][55],cal[55][55];
char mp[55][55];
bool ok[55*55*2];
int main()
{
    //freopen("Input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            getchar();
            for(int j=0;j<m;j++)
                scanf("%c",&mp[i][j]);
        }
        int s = 0,t = 1;
        int cnt = 2;
        memset(ok,false,sizeof(ok));
        memset(row,-1,sizeof(row));
        memset(cal,-1,sizeof(cal));
        for(int i=0;i<n;i++)  //给行编号
        {
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='*'){
                    row[i][j] = cnt;
                    ok[cnt] = true;
                }
                else if(mp[i][j]=='#')
                {
                    if(ok[cnt]==true)
                        cnt++;
                }
            }
             if(ok[cnt]==true)
                cnt++;
        }
        for(int i=2;i<cnt;i++)
            add_Node(s,i,1);
        int ps = cnt;
        for(int j=0;j<m;j++)
        {
            for(int i=0;i<n;i++)
            {
                if(mp[i][j]=='*'){
                    cal[i][j] = cnt;
                    ok[cnt] = true;
                }
                else if(mp[i][j]=='#')
                {
                    if(ok[cnt]==true)
                        cnt++;
                }
            }
            if(ok[cnt]==true)
                cnt++;
        }
        for(int i=ps;i<cnt;i++)
            add_Node(i,t,1);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(row[i][j]>0 && cal[i][j]>0)
                {
                    add_Node(row[i][j],cal[i][j],1);
                }
            }
        }
        int ans = dinci(s,t);
        printf("%d\n",ans);
        Clear(cnt);
    }
    return 0;
}
时间: 2024-10-21 19:12:14

hdoj 5093 Battle ships 【二分图最大匹配】的相关文章

HDOJ 5093 Battle ships 二分图匹配

二分图匹配: 分别按行和列把图展开,hungary二分图匹配.... 样例: 4 4 *ooo o### **#* ooo* 按行展开.... *ooo o#oo oo#o ooo# **#o ooo* ooo* 再按列展开... 7 * 8 *ooooooo oooooooo oooooooo oooooooo *o*ooooo ooooooo* ooooooo* 匹配结果3 Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memo

hdu 5093 Battle ships二分图

二分图最大匹配问题 遇到冰山就把行列拆成两个部分.每个部分x也好,y也好只能匹配一次 图画得比较草,将就着看 横着扫一遍,竖着扫一遍,得到编号 一个位置就对应一个(xi,yi)就是X集到Y集的一条边, 由题意,每个点只能被选择一次.所以最大匹配的边数就是答案了. 算法过程 通常都是先贪心求一个匹配,然后开始增广. 寻找增广路的过程: 一个没有和任意边匹配的点叫做未盖点,从左集X中一个未盖点u出发寻找增广路. 从u出发,选一个非匹配边到达Y集中的v,如果v没匹配,那么就找到一条增广路(只要把之前走

hdu 5093 Battle ships 二分图匹配

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093 一开始就往贪心的方向想了结果wa全场 这种矩阵形式的图一般要联想到行和列构成了二分图 然后实质就是求一个最大匹配 中间的冰山实际上就是把一行或一列切成多个顶点而已 所以一开始预处理一下 然后就可以套用模板 #include <cstring> #include <cstdlib> #include <cstring> #include <cmath> #i

hdu 5093 Battle ships (二部图+最大匹配)

Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 172    Accepted Submission(s): 84 Problem Description Dear contestant, now you are an excellent navy commander, who is responsible o

hdu 5093 Battle ships 最大二分匹配

Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 589    Accepted Submission(s): 233 Problem Description Dear contestant, now you are an excellent navy commander, who is responsible

Battle ships(二分图,建图,好题)

Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1007    Accepted Submission(s): 353 Problem Description Dear contestant, now you are an excellent navy commander, who is responsible

hdu 5093 Battle ships(二分图最大匹配)

题意: M*N的矩阵,每个格子上是三个之一:*.o.#.                     (1 <= m, n <= 50) *:海洋,战船可以停在上面.      o:浮冰,战船不可以停在上面      #:冰山,战船不可以停在上面. 限制:两艘战船不能处于同一行或同一列,除非它们之间有冰山挡着. 问最多可以停多少艘战船. 思路: 和二分图最小点覆盖那道经典题很相似.不过不是求最小点覆盖. 对于每一行,如果连续的一段只能放一艘战船,则将这一段视为同一个点.则每一行都被分为若干个小段,

HDU 5093 Battle ships(二分图匹配)

该题是一道经典的二分图匹配题目 .  同一列(行)上不能放两个船除非有冰山隔着.对于这种二维平面图,我们很容易想到将行和列分成两个集合,进行二分图匹配,当一个行坐标匹配到一个列坐标时,该格子可以放置船.那么为了使任意两个船都不在同一行或者同一列,除非有冰山,我们可以将每一行中一块连续的只能放置一个船的区域都设成一个编号,同样的按照列也这样处理,这样就相当于将行和列缩点了,接下来用最大流模板套一套就可以了 . 处理二分图还有一种更好的算法,叫匈牙利算法,紫书上没有,先用最大流算法解决吧 . 紫书十

[HDOJ5093] Battle ships(最大匹配)

题目链接:https://vjudge.net/problem/HDU-5093 按照行和列分别标注*的id,合并同行或同列相邻的块,二分图两部分分别是行和列,某一点(i,j)则连一条rid(i,j)到cid(i,j)的边.跑最大匹配. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef struct pair<int, int> pii; 5 const int maxn = 110; 6 const int