zoukankan      html  css  js  c++  java
  • 骑士共存问题

    嘟嘟嘟

     

    这是一道比较经典的最小割模型,对只会最大流却对最小割一窍不通的我来说在适合不过了。

    首先,题目中的图片非常良心,细心观察他能得到一个很重要的规律:黄色格子上的骑士只能攻击红色格子上的骑士,反之同理。

    因此,我们可以把棋盘进行黑白染色,然后白点放在图的左侧,黑点在图的右侧,有点像二分图的感觉。

    接下来切入正题了:做最小割的题,源点和汇点往往没有什么实际意义,重点是割掉每一条边的意义。每一条边代表一个冲突,割掉它就是付出的代价。由此可见,最小割一般是反着想,比如源点和汇点不连通了,代表所有冲突解决了。

    具体连边是这样的:

    1.源点像白点连一条边权为1的边,代表如果割掉这条边,就是拿走了这个棋子,代价就是1.

    2.同理黑点向汇点连一条边权为1的边。

    3.考虑一个白点能攻击到的所有黑点,就像这些黑点连一条INF的边。为什么是INF呢?因为这条边的意义代表两个骑士会互相攻击,不能共存,割掉它代表两个骑士能共存了,这显然是不可能的,一次付出的代价是INF。

    4.图中还有障碍点。表示骑士一定不能放到这个点,因此一定会付出1的代价,而不用考虑他是否会割掉,因此不用把他连边建图。

     所以最终的答案就是n2 - minCut - m.

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 4e4 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 
     37 const int dx[10] = {-1, -2, -2, -1, 1, 2, 2, 1}, dy[10] = {-2, -1, 1, 2, 2, 1, -1, -2};
     38 int n, m, t;
     39 bool vis[maxn];
     40 
     41 struct Edge
     42 {
     43     int from, to, cap, flow;
     44 };
     45 vector<Edge> edges;
     46 vector<int> G[maxn];
     47 void addEdge(int from, int to, int w)
     48 {
     49     edges.push_back((Edge){from, to, w, 0});
     50     edges.push_back((Edge){to, from, 0, 0});
     51     int sz = edges.size();
     52     G[from].push_back(sz - 2);
     53     G[to].push_back(sz - 1);
     54 }
     55 
     56 int getnum(int x, int y)
     57 {
     58     return (x - 1) * n + y;
     59 }
     60 
     61 void solve(int x, int y)
     62 {
     63     int u = getnum(x, y);
     64     for(int i = 0; i < 8; ++i)
     65     {
     66         int newx = x + dx[i], newy = y + dy[i];
     67         if(newx > 0 && newx <= n && newy > 0 && newy <= n) 
     68             addEdge(u, getnum(newx, newy), INF);
     69     }
     70 }
     71 
     72 int dis[maxn];
     73 bool bfs()
     74 {
     75     Mem(dis, 0); dis[0] = 1;
     76     queue<int> q; q.push(0);
     77     while(!q.empty())
     78     {
     79         int now = q.front(); q.pop();
     80         for(int i = 0; i < (int)G[now].size(); ++i)
     81         {
     82             Edge& e = edges[G[now][i]];
     83             if(!dis[e.to] && e.cap > e.flow)
     84             {
     85                 dis[e.to] = dis[now] + 1;
     86                 q.push(e.to);    
     87             }
     88         }
     89     }
     90     return dis[t];
     91 }
     92 int cur[maxn];
     93 int dfs(int now, int res)
     94 {
     95     if(now == t || res == 0) return res;
     96     int flow = 0, f;
     97     for(int& i = cur[now]; i < (int)G[now].size(); ++i)
     98     {
     99         Edge& e = edges[G[now][i]];
    100         if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0)
    101         {
    102             e.flow += f;
    103             edges[G[now][i] ^ 1].flow -= f;
    104             flow += f; res -= f;
    105             if(res == 0) break;
    106         }
    107     }
    108     return flow;
    109 }
    110 
    111 int minCut()
    112 {
    113     int flow = 0;
    114     while(bfs())
    115     {
    116         Mem(cur, 0);
    117         flow += dfs(0, INF);
    118     }
    119     return flow;
    120 }
    121 
    122 int main()
    123 {
    124     n = read(); m = read();
    125     t = n * n + 1;
    126     for(int i = 1; i <= m; ++i)
    127     {
    128         int x = read(), y = read();
    129         vis[getnum(x, y)] = 1;
    130     }
    131     for(int i = 1; i <= n; ++i)
    132         for(int j = 1; j <= n; ++j) if(!vis[getnum(i, j)])
    133         {
    134             if((i + j) & 1) addEdge(getnum(i, j), t, 1);
    135             else addEdge(0, getnum(i, j), 1), solve(i, j);
    136         }
    137     write(n * n - m - minCut()); enter;    
    138     return 0;
    139 }
    View Code
  • 相关阅读:
    NetBeans 时事通讯(刊号 # 95 Mar 19, 2010)
    现在才知道TR1的错误在VC9的SP1中解决
    TinyXml快速入门(三)
    Install python 2.6 in CentOS Stack Overflow
    rpm forge install on centos 5
    Linux tee ysdaniel的专栏 博客频道 CSDN.NET
    python26 gramma
    一个简单的基于编辑距离的英文单词查错(Python) Muilpin.Miao的日志 网易博客
    磁盘目录占用空间计算排序工具 ncdu
    PyCon China 2012
  • 原文地址:https://www.cnblogs.com/mrclr/p/9694664.html
Copyright © 2011-2022 走看看