UVALive 6525 二分匹配

UVALive 6525
题目链接:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=92286#problem/A
题意:
一个n*n象棋棋盘上,有一些障碍点。
问最多放置多少个“车”,使得相邻车不会互相攻击。已知他们不能越过障碍点攻击。
思路:
二分匹配。
对于每一行或者每一列,有几个连续段就裂成几个点,如果该点合法即为’.’,则在两个裂出来的点之间可以连一条边。
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
#define inf (1000000000)
const int MAXN = 500 + 5;
int head[MAXN*MAXN], cnt;
struct Edge
{
    int u, v;
    int ne, flow;
    Edge(){}
    Edge(int _u, int _v, int _flow){u = _u, v = _v, flow = _flow, ne = head[_u];}
}edge[MAXN * MAXN * 2];
void add_edge(int u, int v, int flow)
{
    edge[cnt] = Edge(u, v, flow);
    head[u] = cnt++;
    edge[cnt] = Edge(v, u, 0);
    head[v] = cnt++;
}
char str[MAXN][MAXN];
int mark1[MAXN][MAXN], mark2[MAXN][MAXN];
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
bool valid(int x, int y, int n)
{
    for(int i = 0 ; i < 4 ; i++){
        int tx = dx[i] + x;
        int ty = dy[i] + y;
        if(tx < 1 || tx > n)    continue;
        if(ty < 1 || ty > n)    continue;
        if(str[tx][ty] == 'X')  return false;
    }
    return true;
}
void build_graph(int n, int s, int t)
{
    memset(head, -1, sizeof(head));
    cnt = 0;
    int pre1 = 0,  pre2 = 0;
    for(int i = 1 ; i <= n ; i++){
        for(int j = 1 ; j <= n ; j++){
            if(mark1[i][j] != -1 && mark2[i][j] != -1) //&& valid(i, j, n))
                add_edge(mark1[i][j], mark2[i][j], 1);
//                if(mark1[i][j] != pre1 && mark1[i][j] != -1){
//                    pre1 = mark1[i][j];
//                    add_edge(s, mark1[i][j], 1);
                    pre1 = mark1[i][j];
//                }
//                if(mark2[i][j] != pre2 && mark2[i][j] != -1){
//                    pre2 = mark2[i][j];
//                    add_edge(mark2[i][j], t, 1);
                    pre2 = mark2[i][j];
//                }
        }
    }
}
int d[MAXN*MAXN], vis[MAXN*MAXN], num[MAXN*MAXN];
queue<int>que;
int BFS(int t)
{
    memset(vis, 0, sizeof(vis));
    memset(num, 0, sizeof(num));
    int ans = 0;
    d[t] = 0, vis[t] = 1;
    while(!que.empty()) que.pop();
    que.push(t);
    while(!que.empty()){
        int u = que.front();  que.pop();
        num[d[u]]++;
        ans = max(ans, d[u]);
        for(int now = head[u] ; now != -1 ; now = edge[now].ne){
            int v = edge[now].v;
            if(vis[v] == 0) {d[v] = d[u] + 1, vis[v] = 1, que.push(v);}
        }
    }
    return ans;
}
int cur[MAXN*MAXN], p[MAXN*MAXN];
int Augment(int s, int t)
{
    int flow = inf;
    int u = t;
    while(u != s){
        flow = min(flow, edge[p[u]].flow);
        u = edge[p[u]].u;
    }
    u = t;
    while(u != s){
        edge[p[u]].flow -= flow;
        edge[p[u]^1].flow += flow;
        u = edge[p[u]].u;
    }
    return flow;
}
int ISAP(int s, int t)
{
//    printf("s = %d, t = %d\n", s, t);
    int up = BFS(t);
    for(int i = s ; i <= t ; i++)
        cur[i] = head[i];
    int u = s;
    int flow = 0;
    while(d[s] < 2 * t + 1){
//        printf("u = %d\n", u);
        if(u == t){
            flow += Augment(s, t);
            u = s;
        }
        int ok = 0;
        for(int now = cur[u] ; now != -1 ; now = edge[now].ne){
            if(edge[now].flow && d[u] == d[edge[now].v] + 1){
                int v = edge[now].v;
//                printf("first\nv = %d\n", v);
                cur[u] = now;
                p[v] = now;
                u = v;
                ok = 1;
                break;
            }
        }
        if(!ok){
//            printf("second\n");
            int ts = 2 * t;
            for(int now = head[u] ; now != -1 ; now = edge[now].ne)
                if(edge[now].flow){
                    int v = edge[now].v;
                    ts = min(ts, d[v]);
                }
            if(--num[d[u]] == 0)    break;
            num[d[u] = ts + 1]++;
            cur[u] = head[u];
            if(u != s)  u = edge[p[u]].u;
        }
    }
    return flow;
}
int main()
{
//    freopen("UVA 12668.in", "r", stdin);
//    freopen("UVA 12668 data2.out", "w", stdout);
    int n;
    while(scanf("%d", &n) != EOF){
        int sum1 = 0, sum2 = 0;
        memset(mark1, 0, sizeof(mark1));
        memset(mark2, 0, sizeof(mark2));
        int pre = 0;
        for(int i = 1 ; i <= n ; i++){
            scanf("%s", str[i] + 1);
            sum1++;
            for(int j = 1 ; j <= n ; j++){
                if(str[i][j] == 'X' ){
                    sum1++;
                    mark1[i][j] = -1;
                }
                else if(pre != sum1){
                    pre = sum1;
                    mark1[i][j] = sum1;
                }
                else mark1[i][j] = sum1;
//                if(pre != str[i][j]){
//                    pre = str[i][j];
//                    mark1[i][j] = sum1++;
//                }
//                else{
//                    continue;
//                }
            }
        }
        sum2 = sum1;
        for(int j = 1 ; j <= n ; j++){
            sum2++;
            for(int i = 1 ; i <= n ; i++){
                if(str[i][j] == 'X' ){
                    sum2++;
                    mark2[i][j] = -1;
                }
                else if(pre != sum2){
                    pre = sum2;
                    mark2[i][j] = sum2;
                }
                else mark2[i][j] = sum2;
            }
        }
//        printf("mark1\n");
//        for(int i = 1 ; i <= n ; i++){
//            for(int j = 1 ; j <= n ; j++)
//                printf("%d ", mark1[i][j]);
//            printf("\n");
//        }
//        printf("mark1\n");
//        printf("mark2\n");
//        for(int i = 1 ; i <= n ; i++){
//            for(int j = 1 ; j <= n ; j++)
//                printf("%d ", mark2[i][j]);
//            printf("\n");
//        }
//        printf("mark2\n");
//        printf("sum1 = %d, sum2 = %d\n", sum1, sum2);
        int source = 0, sink = sum2 + 1;
        build_graph(n, source, sink);
        for(int i = 1 ; i <= sum1 ; i++)
            add_edge(0, i, 1);
        for(int j = sum1 + 1 ; j <= sum2 ; j++)
            add_edge(j, sum2 + 1, 1);
        int ans = ISAP(source, sink);
//        int temp = 0;
//        if(sum1 > sum2 - sum1){
//            for(int i = 1 ; i <= n ; i++){
//                int f = 1;
//                for(int j = 1 ; j <= n ; j++){
//                    if(mark1[i][j] == -1)   {f = 1; continue;}
//                    else if(f == 1) f = 0, temp++;
//                }
//            }
//        }
//        else{
//            for(int i = 1 ; i <= n ; i++){
//                int f = 1;
//                for(int j = 1 ; j <= n ; j++){
//                    if(mark2[i][j] == -1)   {f = 1; continue;}
//                    else if(f == 1) f = 0, temp++;
//                }
//            }
//        }
//        ans = temp - ans;
//        ans = max(sum1, sum2) - ans - n;
        printf("%d\n", ans);
    }
    return 0;
}
/*
4
.XX.
.XX.
XX.X
.XX.
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值