Luogu P5030 长脖子鹿放置(网络流)

匈牙利T了,Dinic飞了。。。
按奇偶连

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define R(a,b,c) for(register int a = (b); (a) <= (c); ++(a))
#define nR(a,b,c) for(register int a = (b); (a) >= (c); --(a))
#define Fill(a,b) memset(a, b, sizeof(a))
#define Swap(a,b) ((a) ^= (b) ^= (a) ^= (b))
#define ll long long
#define u32 unsigned int
#define u64 unsigned long long
 
#define ON_DEBUGG
 
#ifdef ON_DEBUGG
 
#define D_e_Line printf("\n----------\n")
#define D_e(x) cout << (#x) << " : " << x << endl
#define Pause() system("pause")
#define FileOpen() freopen("in.txt", "r", stdin)
#define FileSave() freopen("out.txt", "w", stdout)
#include <ctime>
#define TIME() fprintf(stderr, "\ntime: %.3fms\n", clock() * 1000.0 / CLOCKS_PER_SEC);
  
#else
 
#define D_e_Line ;
#define D_e(x) ;
#define Pause() ;
#define FileOpen() ;
#define FileSave() ;
#define TIME() ;
//char buf[1 << 21], *p1 = buf, *p2 = buf;
//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
 
#endif
 
using namespace std;
struct ios{
    template<typename ATP>inline ios& operator >> (ATP &x){
        x = 0; int f = 1; char ch;
        for(ch = getchar(); ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
        while(ch >= '0' && ch <= '9') x = x * 10 + (ch ^ '0'), ch = getchar();
        x *= f;
        return *this;
    }
}io;
 
template<typename ATP>inline ATP Max(ATP a, ATP b){
    return a > b ? a : b;
}
template<typename ATP>inline ATP Min(ATP a, ATP b){
    return a < b ? a : b;
}
template<typename ATP>inline ATP Abs(ATP a){
    return a < 0 ? -a : a;
}

const int N = 207;
const int M = 500007;

int n, m;
int S, T;
struct Edge{
    int nxt, pre, w;
}e[M];
int head[M], cntEdge = 1;
inline void add(int u, int v, int w){
    e[++cntEdge] = (Edge) { head[u], v, w}, head[u] = cntEdge;
}
inline void Add(int u, int v, int w){
    add(u, v, w);
    add(v, u, 0);
}

int cur[M];
int q[M], d[M];
inline bool BFS(){
    int h = 0, t = 1;
    R(i,S,T) d[i] = -1;
    d[S] = 0, q[0] = S;
    while(h != t){
        int u = q[h++];
        if(h > 500000) h = 0; 
        for(register int i = head[u]; i; i = e[i].nxt){
            int v = e[i].pre;
            if(e[i].w && d[v] == -1){
                d[v] = d[u] + 1;
                q[t++] = e[i].pre;
                if(t > 500000) t = 0;
            }
        }
    }
    return d[T] != -1;
}
inline int DFS(int u, int f){
    if(u == T) return f;
    int w, used = 0;
    for(register int i = cur[u]; i; i = e[i].nxt){
        int v = e[i].pre;
        if(d[v] == d[u] + 1){
            w = DFS(v, Min(f - used, e[i].w));
            e[i].w -= w, e[i ^ 1].w += w;
            used += w;
            if(used == f) return f;
        }
    }
    if(!used) d[u] = -1;
    return used;
}
inline int Dinic(){
    int sum = 0;
    while(BFS()){
        R(i,S,T) cur[i] = head[i];
        sum += DFS(S, 0x7fffffff);
    }
    return sum;
}
inline int ID(int x, int y){
    return (x - 1) * m + y;
}

int mark[N][N];
int dx[] = {3, 3, 1, 1, -3, -3, -1, -1}, dy[] = {1, -1, 3, -3, 1, -1, 3, -3};
int main(){
    int K;
    io >> n >> m >> K;
    S = 0, T = n * m + 1;
    R(i,1,K){
        int x, y;
        io >> x >> y;
        mark[x][y] = true;
    }
    R(i,1,n){
        R(j,1,m){
            int id = ID(i, j);
            if(i & 1){
                Add(S, id, 1);
            }
            else{
                Add(id, T, 1);
            }
        }
    }
    R(i,1,n){
        R(j,1,m){
            if(mark[i][j]) continue;
            int id = ID(i, j);
            if(i & 1){
                R(k,0,7){
                    int fx = i + dx[k], fy = j + dy[k];
                    if(fx < 1 || fx > n || fy < 1 || fy > m || mark[fx][fy]) continue;
                    int id2 = ID(fx, fy);
                    Add(id, id2, 1);
                }
            }
        }
    }
    
    printf("%d", n * m - K - Dinic());
    return 0;
}

转载于:https://www.cnblogs.com/bingoyes/p/11568340.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值