[SHOI 2007] 善意的投票

[题目链接]

https://www.lydsy.com/JudgeOnline/problem.php?id=1934

[算法]

首先 , 选择睡觉的人和不选择睡觉的人构成两个集合

这启发我们用最小割解决该问题 :

1. 将源点与每个睡觉的人连边 , 将每个不睡觉的人与汇点连边 , 割掉这样的一条边的含义是 : 有一个人放弃了睡觉 / 不睡觉 , 产生了1冲突

2. 将朋友之间连边 , 格调这样一条边的含义是 : 这两个人产生了冲突

求解这个图的最小割即可

时间复杂度 : O(dinic(N , M))

[代码]

#include<bits/stdc++.h>
using namespace std;
#define N 310
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int inf = 1e9;

struct edge
{
    int to , w , nxt;
} e[N * N * 4];

int tot , n , m , S , T;
int head[N] , dep[N];

template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void read(T &x)
{
   T f = 1; x = 0;
   char c = getchar();
   for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -f;
   for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - ‘0‘;
   x *= f;
}
inline void addedge(int u , int v , int w)
{
    ++tot;
    e[tot] = (edge){v , w , head[u]};
    head[u] = tot;
    ++tot;
    e[tot] = (edge){u , 0 , head[v]};
    head[v] = tot;
}
inline bool bfs(int s)
{
    queue< int > q;
    memset(dep , 255 , sizeof(dep));
    q.push(s);
    dep[s] = 1;
    while (!q.empty())
    {
        int cur = q.front();
        q.pop();
        for (int i = head[cur]; i; i = e[i].nxt)
        {
            int v = e[i].to , w = e[i].w;
            if (w > 0 && dep[v] == -1)
            {
                dep[v] = dep[cur] + 1;
                q.push(v);
                if (v == T) return true;
            }
        }
    }
    return false;
}
inline int dinic(int u , int flow)
{
    int rest = flow;
    if (u == T)
        return flow;
    for (int i = head[u]; i && rest; i = e[i].nxt)
    {
        int v = e[i].to , w = e[i].w;
        if (w > 0 && dep[v] == dep[u] + 1)
        {
            int k = dinic(v , min(rest , w));
            if (!k) dep[v] = 0;
            rest -= k;
            e[i].w -= k;
            e[i ^ 1].w += k;
        }
    }
    return flow - rest;
}

int main()
{

    read(n); read(m);
    tot = 1;
    S = n + 1 , T = S + 1;
    for (int i = 1; i <= n; i++)
    {
        int x;
        read(x);
        if (!x) addedge(S , i , 1);
        else addedge(i , T , 1);
    }
    for (int i = 1; i <= m; i++)
    {
        int x , y;
        read(x); read(y);
        addedge(x , y , 1);
        addedge(y , x , 1);
    }
    int ans = 0;
    while (bfs(S))
    {
        while (int flow = dinic(S , inf)) ans += flow;
    }
    printf("%d\n" , ans);

    return 0;
}

原文地址:https://www.cnblogs.com/evenbao/p/10355663.html

时间: 2024-08-30 14:06:53

[SHOI 2007] 善意的投票的相关文章

[SHTSC 2007] 善意的投票

我就是来复习Dinic算法的,仅10天不写,我已经退化成写一遍+调试需要接近一个小时了,当然其中不乏在网上乱逛的时间… 赞成从S源点连一条单向边,反对向T汇点连一条单向边,朋友关系连双向边. 但是总感觉自己看到题目不能一下想到这是网络流,感觉这些题都是给一个图,求最优之类. program vote; type ptype=^node; node=record v,w,flow:longint; op,next:ptype; end; const maxn=310; var head:array

「SHOI2007」「Codevs2341」 善意的投票

2341 善意的投票 2007年省队选拔赛上海市队选拔赛 时间限制: 5 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数. 我们的问题就是,每位小朋友

C++之路进阶——最大流(善意的投票)

F.A.Qs Home Discuss ProblemSet Status Ranklist Contest ModifyUser  hyxzc Logout 捐赠本站 Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入.输出语句及数据类型及范围,避免无谓的RE出现. 1934: [Shoi2007]Vote 善意的投票 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 1646  Solved: 1006[

BZOJ 1934: [Shoi2007]Vote 善意的投票 最小割

1934: [Shoi2007]Vote 善意的投票 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1934 Description 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数

1934: [Shoi2007]Vote 善意的投票

1934: [Shoi2007]Vote 善意的投票 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 1174  Solved: 723[Submit][Status] Description 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所

洛谷 P2057 善意的投票(网络流最小割)

P2057 善意的投票 题目描述 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数. 我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小? 输入输出格式 输入格式: 文件的第一行只有两个整数n,m,保证有2≤n≤300,1≤m≤n(n-1)/2.其中

luoguP2057善意的投票

理解下题意: 题意大致就是有n个人有两种不同的意见并且有许多朋友,需要让朋友间尽可能的统一意见(少发生冲突),如果一个人违反自己的本意也算冲突,求最少的冲突... 思路: 明眼人直接发现是最小割,两种意见可以看作源点S和T,我们需要做的是割最少的边使得S和T成为两个不同的集合,解释:割掉的边相当于1次冲突(因为若某边被割走,则显然这条边相连的两个点分别通向了S和T,所以算是一次冲突),当S和T还连通时则必然存在一条路径,这样肯定会有冲突,所以需要使得S和T孤立. 实现: 实现时这样建图:直接将S

【BZOJ】【1934】【SHOI 2007】Vote 善意的投票

网络流/最小割 简单题= =直接利用最小割的性质: 割掉这些边后,将所有点分成了两部分(两个连通块),我们可以假定与S相连的是投赞成票,与T相连的是投反对票. 那么如果一个小朋友原本意愿是睡觉,那么连边 S->i ,边权为1,表示如果割掉这条边(即让他投违反意愿的票)则冲突数+1.原本意愿是不睡觉的连 i->T,边权为1,意义同理. 然后处理“好朋友”的情况,对每对好朋友,连边 i->j 和 j->i,边权均为1,表示如果割掉这条边(则两个点所属不同块)则冲突数+1. 要求总冲突数

BZOJ 1934 [Shoi2007]Vote 善意的投票(最小割)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1934 [题目大意] 每个人对于投票都有自己原来的观点:1或者0, 他可以违背自己原来的意愿投相反的票, 同时存在一些相互的朋友关系, 我们定义一次投票的冲突数为好朋友之间发生冲突的总数, 加上和所有和自己本来意愿发生冲突的人数. 求最小冲突. [题解] 我们将好友之间连双向边,流量为1,对于原本意愿为1的连源点,0的连汇点,流量为1, 该图最小割即为最小冲突. [代码] #inclu