[SHOI2007]善意的投票

嘟嘟嘟

看数据范围,加上题中频繁提到的冲突,就可以想到算法是最小割。

1.同意睡觉的,源点就像他连一条容量为1的边。割掉它就代表他背叛了自己的意愿。

2.同理,不同意睡觉的,就像汇点连一条边。

3.考虑每一对朋友。如果两个朋友意见相反,就互相连一条容量为1的边,割掉其中的任意一条就代表朋友之间发生了冲突,代价为1.而且根据网络流性质,一定不会同时割掉这两条边。

4.如果一对朋友之间意见相同呢?其实还是建边还是和上面一样。因为如果割掉这条边的原因一定是其中一个人为了照顾和自己意见相反的其他朋友,而和这个朋友发生了冲突。

画一个图:

1,2同意睡觉,且是朋友;3,4不同意睡觉;并且1和3,1和4还是朋友。

最小割为2,可以有这么几个典型情况:

1.割掉边(6), (7):3和4为了照顾1,变卦了。

2.割掉边(4), (5):1分别和3, 4发生冲突。

3.割掉边(1), (3):1为了照顾3和4,变卦了,因此与2发生了冲突。

放代码啦:

  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 = 305;
 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 int n, m, t;
 38
 39 struct Edge
 40 {
 41     int from, to, cap, flow;
 42 };
 43 vector<Edge> edges;
 44 vector<int> G[maxn];
 45 void addEdge(int from, int to)
 46 {
 47     edges.push_back((Edge){from, to, 1, 0});
 48     edges.push_back((Edge){to, from, 0, 0});
 49     int sz = edges.size();
 50     G[from].push_back(sz - 2);
 51     G[to].push_back(sz - 1);
 52 }
 53
 54 int dis[maxn];
 55 bool bfs()
 56 {
 57     Mem(dis, 0); dis[0] = 1;
 58     queue<int> q; q.push(0);
 59     while(!q.empty())
 60     {
 61         int now = q.front(); q.pop();
 62         for(int i = 0; i < (int)G[now].size(); ++i)
 63         {
 64             Edge& e = edges[G[now][i]];
 65             if(!dis[e.to] && e.cap > e.flow)
 66             {
 67                 dis[e.to] = dis[now] + 1;
 68                 q.push(e.to);
 69             }
 70         }
 71     }
 72 //    for(int i = 1; i <= n; ++i) printf("%d ", dis[t]); enter;
 73     return dis[t];
 74 }
 75 int cur[maxn];
 76 int dfs(int now, int res)
 77 {
 78     if(now == t || res == 0) return res;
 79     int flow = 0, f;
 80     for(int& i = cur[now]; i < (int)G[now].size(); ++i)
 81     {
 82         Edge& e = edges[G[now][i]];
 83         if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0)
 84         {
 85             e.flow += f;
 86             edges[G[now][i] ^ 1].flow -= f;
 87             flow += f; res -= f;
 88             if(res == 0) break;
 89         }
 90     }
 91     return flow;
 92 }
 93
 94 int minCut()
 95 {
 96     int flow = 0;
 97     while(bfs())
 98     {
 99         Mem(cur, 0);
100         flow += dfs(0, INF);
101     }
102     return flow;
103 }
104
105 int main()
106 {
107     n = read(); m = read();
108     t = n + 1;
109     for(int i = 1; i <= n; ++i)
110     {
111         int x = read();
112         if(x) addEdge(0, i);
113         else addEdge(i, t);
114     }
115     for(int i = 1; i <= m; ++i)
116     {
117         int x = read(), y = read();
118         addEdge(x, y); addEdge(y, x);
119     }
120     write(minCut()); enter;
121     return 0;
122 }

原文地址:https://www.cnblogs.com/mrclr/p/9696426.html

时间: 2025-01-17 06:07:47

[SHOI2007]善意的投票的相关文章

BZOJ1934:[SHOI2007]善意的投票 &amp; BZOJ2768:[JLOI2010]冠军调查——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=1934 https://www.lydsy.com/JudgeOnline/problem.php?id=2768 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲

p2057 [SHOI2007]善意的投票

传送门 分析 权值不同点之间连权值为1的边 起点向每个1,每个0向终点也连权值为1的边 跑最小割即可 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<

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个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所

「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[

[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

洛谷 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