最小割 ---- 集合冲突模型

集合冲突模型

1.问题形式
有 n 个物品和两个集合 S,T。将一个物品放入 S 集合会花费 ai,放入 T 集合会花费 bi。还有若干个形如 u,v,w 限制条件,表示如果 u 和 v 同时不在一个集合会花费 w。每个物品必须且只能属于一个集合,求最小的代价。
2.解决方法

  1. 我们对于每个集合设置源点 S 和汇点 T
  2. 第 i 个点由 S 连一条容量为 bi的边、向 T 连一条容量为 ai的边。
  3. 对于限制条件 u,v,w,我们在 u,v 之间连容量为 w 的双向边。
  4. 注意到当 S 和 T 不相连时,S 能到达 i 代表物品 i 放入 S,i 能到达 T 代表物品 i 放入 T。
  5. 当割开 S→i 的边,意味着 i 放入 T;当割开 i→T 的边,意味着 i 放入 S;
  6. 当割开 u,v 之间的边,意味着 u,v 不放入同一个集合。因此最小割就是最小花费。

对于每个割集都对应一种集合划分方式
就是把1和2都放道T里面
在这里插入图片描述
这个是把1和2放到S里面

在这里插入图片描述
这是把1和2分开放!!
在这里插入图片描述


bzoj1934


题目大意:

n个人有两种不同的意见并且有许多朋友,需要让朋友间尽可能的统一意见(少发生冲突),如果一个人违反自己的本意也算冲突,求最少的冲突?


解题思路:

首先把人分成两份,意见为1的与源点连边,容量为1,否则与汇点连边,容量也设为1,表示更改自己意见的代价。
接着对每一对朋友之间连一条双向边,容量为1,表示朋友之间的冲突。


#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 dp[maxn];
int arr[maxn], num;
int maxs = -1;

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 main() {
	int tn, tm; 
	scanf("%d%d", &tn, &tm);
    s = 0, t = tn + 1;
    n = t;
    memset(head, -1, sizeof head);
    for(int i = 1;i <= tn; ++ i){
        int x;
        scanf("%d", &x);
        if(x)add(s, i, 1),add(i, s, 0);
        
        else add(i, t, 1), add(t, i, 0);
    }
    while(tm --){
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y, 1);
        add(y, x, 1);
    }
    printf("%lld\n",get_maxflow());
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值