Luogu P2057 [SHOI2007]善意的投票___最小割

题目大意:

n n n个人,每个人有一个意愿 0 0 0 1 1 1
m m m对关系,表示 ( i , j ) (i,j) (i,j)是一对好朋友,即意愿应该相同
求最小冲突
冲突数为 与 自 身 意 愿 冲 突 人 数 + 与 好 友 意 愿 冲 突 人 数 与自身意愿冲突人数+与好友意愿冲突人数 +

分析:

明显是求最小割
考虑建立源点汇点 S , T S,T S,T
S − > 意 愿 为 0 S->意愿为0 S>0
意 愿 为 1 − > T 意愿为1->T 1>T
③好友间连边
考虑就是使得不存在 S − > 意 愿 为 0 − > 意 愿 为 1 − > T S->意愿为0->意愿为1->T S>0>1>T这种路径
那就是最小割,网络流即可

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>
 
#define inf 0x3f3f3f3f
#define N 305
 
using namespace std;
 
struct Node { int To, w, nxt; }e[N*N*2];
int A[N][N], id[N], dis[2*N*N], ls[2*N*N], n, m, d, cnt = 1, tot = 0, Total = 0, Maxflow = 0, S, T;
char s[N];
int num[2];

int Numid(int x, int y)
{
    return (x - 1) * m + y;
}
 
void Addedge(int u, int v, int w)
{
    e[++cnt].To = v, e[cnt].nxt = ls[u], e[cnt].w = w, ls[u] = cnt;
    e[++cnt].To = u, e[cnt].nxt = ls[v], e[cnt].w = 0, ls[v] = cnt;
}
 
bool Checkjl(int ax, int ay, int bx, int by)
{
    return (((ax - bx) * (ax - bx) + (ay - by) * (ay - by)) <= (d * d));     
}
 
queue <int> Q;
 
bool bfs()
{
    while (Q.size()) Q.pop();
    for (int i = S; i <= T; i++) dis[i] = 0;
    dis[S] = 1;
    Q.push(S);
    while (Q.size())
    {
        int u = Q.front(); Q.pop();
        for (int i = ls[u]; i; i = e[i].nxt)
            if (e[i].w && !dis[e[i].To])
            {
                dis[e[i].To] = dis[u] + 1;
                if (e[i].To == T) return 1;
                Q.push(e[i].To); 
            }
    }
    return 0;
}
 
int dfs(int u, int flow)
{
    if (u == T) return flow;
    int rest = flow, rp = 0;
    for (int i = ls[u]; i && rest; i = e[i].nxt)
        if (dis[e[i].To] == dis[u] + 1 && e[i].w)
        {
            rp = dfs(e[i].To, min(rest, e[i].w));
            if (!rp) dis[e[i].To] = 0;
            e[i].w -= rp;
            e[i^1].w += rp;
            rest -= rp;
        }
    return flow - rest;
}
 
void dinic()
{
    int flow;
    while (bfs())
        while (flow = dfs(S, inf)) Maxflow += flow; 
}
 
int main() 
{
//	freopen("data.in", "r", stdin);
    scanf("%d%d", &n, &m);
    S = 0, T = n + 1;
	int x, y;
	for (int i = 1; i <= n; i++) 
	{
		scanf("%d", &id[i]);
		if (!id[i]) Addedge(i, T, 1); else Addedge(S, i, 1);
	} 
	for (int i = 1; i <= m; i++) 
	{   
        scanf("%d%d", &x, &y);
        Addedge(x, y, 1); Addedge(y, x, 1);
	}
    dinic();
    printf("%d\n", Maxflow);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值