ZOJ 1654_Place the Robots(建立二分图)

来源:互联网 发布:ipv6加端口号访问 编辑:程序博客网 时间:2024/05/12 07:41

二分图概念及其相关算法:http://www.renfei.org/blog/bipartite-matching.html

本题难在如何建立二分图,详情看注释:

//MJRT#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>//////////////////////#include<iostream>#include<algorithm>#include<string>#include <iterator>#include<sstream>#include<functional>#include<numeric>///////////////////////#include<vector>#include<map>#include <stack>#include<queue>#include<set>#include <bitset>#include <list>using namespace std;#define lch(x)  ((x) << 1)#define rch(x) ((x)<<1|1)#define dad(x) ((x)>>1)#define lowbit(x) ((x)&(-x))static int INDEX = 0,BUGs = 0;#define BUG() cout << "There is BUG No." << BUGs++ <<endl;#define Whats(x) cout << "{ "<< #x << " }" << " is " << "*** "<< x << " ***" << "  index:" << INDEX++ <<endl;#define Show(x,s,l)         cout << #x << ": "; for(int i = s ; i < s+l ; i++) cout << x[i] << " ";  cout << "\n";#define Clear(name) memset(name, 0, sizeof(name));typedef  long long int LL;const int INF = ~0U>>1;struct Point{    int x,y;    Point(int x,int y):x(x),y(y){}    Point(){}};struct Line{    Point s,e;    Line(Point s,Point e):s(s),e(e){}    Line(){}    bool operator ^ (const Line & b) const    {        return            max(s.x,e.x) >= min(b.s.x,b.e.x) &&            max(b.s.x,b.e.x) >= min(s.x,e.x) &&            max(s.y,e.y) >= min(b.s.y,b.e.y) &&            max(b.s.y,b.e.y) >= min(s.y,e.y) ;    }};const int N = 5 + 1250;char maze[N][N];bool mp[N][N];int mark[N];bool vis[N];int m,n;vector<Line> row,col;bool dfs(int x);int main(){    //ios::sync_with_stdio(false);#ifndef ONLINE_JUDGE    //freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);#endif    int Case,tot=1;    scanf("%d",&Case);    while(Case--)    {        scanf("%d%d",&m,&n);        Clear(maze);        for(int i = 0 ;i < m ; i++)    scanf("%s",&maze[i]);//计算横着的联通块(需包含空地o)        row.clear();        row.push_back(Line(Point(0,0),Point(0,0)));        for(int i = 0 ;i < m ; i++)        {            bool ok = 0;            for(int j = 0 ; j < n ; )            {                while(maze[i][j] == '#' && j < n) j++;                int s = j;                while(maze[i][j] != '#' && j < n) j++;                int e = j-1;                for(int k = s ; k <= e ; k++)    if(maze[i][k]=='o') {ok=1 ; break;}                if(s == e && maze[i][s] != 'o')  ok = 0;                if(ok&&s<=e)  row.push_back(Line(Point(i,s),Point(i,e)));            }        }//计算竖着的联通块(需包含空地o)        col.clear();        col.push_back(Line(Point(0,0),Point(0,0)));        for(int i = 0 ; i < n ; i++)        {            bool ok = 0;            for(int j = 0 ; j < m ; )            {                while(maze[j][i] == '#' && j < m) j++;                int s = j;                while(maze[j][i] != '#' && j < m) j++;                int e = j-1;                for(int k = s ; k <= e ; k++)    if(maze[k][i]=='o') {ok=1 ; break;}                if(s == e && maze[s][i] != 'o')  ok = 0;                if(ok && s<=e )  col.push_back(Line(Point(s,i),Point(e,i)));            }        }//建立二分图//如果横着的联通块和竖着的联通块相交 且 交点是空地o ,我们认为他们是匹配的        Clear(mp);        for(int i = 1 ; i < row.size() ; i++ )            for(int j = 1 ; j < col.size() ; j++ )                if(row[i] ^ col[j] && maze[ row[i].s.x ][ col[j].s.y ] == 'o')                    mp[i][j] = 1;//为了方便重载n,m为二分图的长和宽        m = row.size()-1;        n = col.size()-1;        int cnt = 0;        Clear(mark);        for(int i = 1 ; i <= m ;i++)        {            Clear(vis);            if(dfs(i)) cnt++;            //else Whats(i);        }        int res = cnt;        printf("Case :%d\n",tot++);        printf("%d\n",res);    }    return 0;}bool dfs(int x){    for(int i = 1 ; i<= n ; i++)    {        if(!mp[x][i] || vis[i] )  continue;        vis[i] = 1;        if(!mark[i] || dfs(mark[i]))        {            mark[i] = x;            return 1;        }    }    return 0;}
0 0
原创粉丝点击