最小割 ---- 二分图最大独立集(集合冲突模型) ---- 骑士共存 方格取数(网络流24题)

二分图独立集

定理: 二分图最大独立集=n - 二分图最大匹配

其实二分图独立集是特殊的一种最大权闭合子图。我们根据上文“收益”的思想,把选某个点的收益看为1,左部节点为正权点,右部节点为负权点.按照最大权闭合子图的方式建图,答案为正权和-最小割=n-最小割=n-最大流。我们发现把最大权闭合子图中INF的边换成1也不影响答案,因为图中其他边的容量都为1。这样图就变成了二分图匹配中的图,最大流=二分图最大匹配


方格取数

题目大意:

现在就是每个方格里面都有一个数值,但是你选了一个方格之后,它上下左右的都不能选了问你现在取出的数最大的和是多少?


解题思路:

  1. 现在就是我们要求和最大,那么就是冲突的数字要最小,那么我们把冲突这种关系表现为图的联通性的时候那么我们就可以用最小割去求解,就是假如这有两个数是冲突了,在图中就是他们同时存在的时候图是联通的!!

  2. 那么我们观察一下点就是上下左右的点:我们对棋盘进行黑白染色((横坐标+纵坐标)%2==1的点设为黑点),可以发现,若取一个黑格的点,受到影响的就是周围的白点。

  3. 然后可以发现这是一个最小割的套路题,假设所有的点都取,然后去掉最小割,就是答案了。
    建模:S->黑点,容量为点权
    白点->T,容量为点权
    每一个黑点->取该黑点会受到影响的白点,容量为inf
    然后就可以了


代码:

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)  {
   read(first);
   read(args...);
}
struct node {
   int to, next, len; 
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
   e[cnt] = {to,head[from],len};
   head[from] = cnt ++;
}

int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];

bool bfs() {
   ms(d,0);
   queue<int> q;
   q.push(s); d[s] = 1;
   while(!q.empty()) {
      int u = q.front(); q.pop();
      for(int i = head[u]; ~i; i = e[i].next) {
         int v = e[i].to;
         if(d[v] || e[i].len <= 0) continue;
         q.push(v);
         d[v] = d[u] + 1;
      }

   }      
   for(int i = 0; i <= n; ++ i) cur[i] = head[i];
   return d[t] != 0;
}

int dfs(int u, int flow) {
    if(u == t) return flow;
    for(int &i = cur[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
        int delta = dfs(v,min(flow,e[i].len));
        if(delta <= 0) continue;
        e[i].len -= delta;
        e[i^1].len += delta;
        return delta;
    }
    return 0;
}

int get_maxflow() {
    int maxFlow = 0, delta;
    while(bfs())//bfs进行构建最短路网络
         while(delta = dfs(s,INF))
             maxFlow += delta;
    return maxFlow;
}
int Tn, Tm;
int nx[] = {-1,0,1,0};
int ny[] = {0,1,0,-1};
int sum = 0;
int main() {
   IOS;
   ms(head,-1);
   cin >> Tm >> Tn;
   s = 0, t = Tm * Tn + 1;
   n = t;
   for(int i = 1; i <= Tm; ++ i) {
      for(int j = 1; j <= Tn; ++ j) {
         int x;
         cin >> x;
         sum += x;
         if((i + j) & 1) add(s,(i-1)*Tn+j,x), add((i-1)*Tn+j,s,0);
         else add((i-1)*Tn+j,t,x), add(t,(i-1)*Tn+j,0);
      }
   }

   for(int i = 1; i <= Tm; ++ i) {
      for(int j = 1; j <= Tn; ++ j) {
         if((i + j) & 1) {
            for(int k = 0; k <= 3; ++ k) {
               int ni = i + nx[k];
               int nj = j + ny[k];
               if(ni < 1 || nj < 1 || ni > Tm || nj > Tn) continue;
               add((i-1)*Tn+j,(ni-1)*Tn+nj,INF);
               add((ni-1)*Tn+nj,(i-1)*Tn+j,0);
            }
         } 
      }
   }
   cout << sum - get_maxflow();
   return 0;
}

骑士共存


代码:

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)  {
   read(first);
   read(args...);
}
struct node {
   int to, next, len; 
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
   e[cnt] = {to,head[from],len};
   head[from] = cnt ++;
}

int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];

bool bfs() {
   ms(d,0);
   queue<int> q;
   q.push(s); d[s] = 1;
   while(!q.empty()) {
      int u = q.front(); q.pop();
      for(int i = head[u]; ~i; i = e[i].next) {
         int v = e[i].to;
         if(d[v] || e[i].len <= 0) continue;
         q.push(v);
         d[v] = d[u] + 1;
      }

   }      
   for(int i = 0; i <= n; ++ i) cur[i] = head[i];
   return d[t] != 0;
}

int dfs(int u, int flow) {
    if(u == t) return flow;
    for(int &i = cur[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
        int delta = dfs(v,min(flow,e[i].len));
        if(delta <= 0) continue;
        e[i].len -= delta;
        e[i^1].len += delta;
        return delta;
    }
    return 0;
}

int get_maxflow() {
    int maxFlow = 0, delta;
    while(bfs())//bfs进行构建最短路网络
         while(delta = dfs(s,INF))
             maxFlow += delta;
    return maxFlow;
}
int Tn, Tm;
int Map[202][202];
int nx[] = {2,2,-2,-2,-1,-1,1,1};
int ny[] = {-1,1,-1,1,2,-2,2,-2};
int sum = 0;
int main() {
   IOS;
   ms(head,-1);
   cin >> Tn >> Tm;
   for(int i = 1; i <= Tm; ++ i) {
      int x, y;
      cin >> x >> y;
      Map[x][y] = 1;
   }
   s = 0, t = Tn * Tn + 1;
   n = t;
   for(int i = 1; i <= Tn; ++ i) {
      for(int j = 1; j <= Tn; ++ j) {
         if(Map[i][j]) continue;
         if((i+j)&1) add(s,(i-1)*Tn+j,1), add((i-1)*Tn+j,s,0);
         else add((i-1)*Tn+j,t,1), add(t,(i-1)*Tn+j,0);
      }
   }
   int sum = Tn * Tn;
   for(int i = 1; i <= Tn; ++ i) {
      for(int j = 1; j <= Tn; ++ j) {
         if((i+j)&1 && !Map[i][j]) {
            for(int k = 0; k < 8; ++ k) {
               int ni = i + nx[k];
               int nj = j + ny[k];
               if(Map[ni][nj] || ni < 1 || nj < 1 || ni > Tn || nj > Tn) continue;
               add((i-1)*Tn+j,(ni-1)*Tn+nj,INF);
               add((ni-1)*Tn+nj,(i-1)*Tn+j,0);
            }
         }
      }
   }
   cout << sum - get_maxflow() - Tm;
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值