[SHOI2007]善意的投票

题意:

洛谷链接

n 个小朋友投票睡不睡午觉,每个人都有自己的想法,有 m 对朋友关系,如果朋友之间投票不一样则为发生冲突,但每个人可以投与自己想法相反的票,但改变想法也算一个冲突,怎样使得冲突最小,输出最小冲突数量。(2n300,1mn(n1)2)


由数据范围容易联想到网络流做法,但就是不知道怎么建图。

将所有的冲突连成边,比如 A 想睡觉,B 不想,那么 A>B 表示 AB 冲突,想要接受这个冲突就要花费 1 的代价。

如果割掉所有的冲突那么就相当于考虑完所有的代价,所以建完图后跑个最小割。

具体建图的话:
1.将所有想睡觉的连向源点;
2.将所有不想睡觉的连向汇点;
3.将所有朋友关系连上边,这里注意睡觉的向不睡觉的连单向边,意见相同的要互相连双向边。(然而为了方便起见我们可以都连双向边,不会有影响)

网络流建出来的图一般都很玄学,但我们可以举几个简单的例子来思考每条边的意义:

如上图,1 想睡觉,23 不想,如果意见都保持不变相当于割掉 1 连向 23 的边,代价为 2。但是如果我们只让 1 改变为不想睡觉,相当于割掉 s 连向 1 的边,代价更小为 1。所以,割掉睡觉向不睡觉的边相当于保持冲突,割掉 s 连向睡觉的边或不睡觉连向 t 的边相当于改变想法。

如上图,如果像刚才那样改变 1 的想法,就是割掉了 s1 的边,但是通过 45 同样可以和 23 流,因为改变了 1 的想法后与 45 又产生了新的冲突,我们需要继续割掉 s 连向 45 的边,就是将 145 的想法都改变,显然不如让 123 冲突更优。所以,相同想法的点建边是为了保证具有相同的想法,如果有一边改变的话这条边也需要被割掉。

理解的差不多,剩下的就是板子了 qwq

#include <bits/stdc++.h> using namespace std; const int N=301010; const int inf=0x3f3f3f3f; int n,m,s,t,cnt=1; int a[N]; struct E{ int to,nxt,cap; } e[N]; int head[N],cur[N]; int dep[N],vis[N]; queue <int> q; inline int read() { int sum = 0, f = 1; char c = getchar(); while(c<'0' || c>'9') { if(c=='-') f = -1; c = getchar(); } while(c>='0'&&c<='9') { sum = sum * 10 + c - '0'; c = getchar(); } return sum * f; } inline void add(int u,int v,int w) { e[++cnt] = (E){ v,head[u],w }; head[u] = cnt; e[++cnt] = (E){ u,head[v],0 }; head[v] = cnt; } bool SPFA() { memset(dep,0x3f,sizeof(dep)); memset(vis,0,sizeof(vis)); for(int i=s;i<=t;i++) cur[i] = head[i]; int now = dep[1]; dep[s] = 0; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i=head[u]; i; i=e[i].nxt) { int v = e[i].to; if(e[i].cap && dep[v] > dep[u]+1) { dep[v] = dep[u]+1; if(vis[v]) continue; q.push(v); vis[v] = 1; } } } return now != dep[t]; } int DFS(int u,int flow) { if(u==t || !flow) return flow; int dinic = 0, f; for(int i=cur[u]; i; i=e[i].nxt) { cur[u] = i; int v = e[i].to; if(e[i].cap && dep[v]==dep[u]+1) { f = DFS( v, min(flow-dinic,e[i].cap) ); if(f) { dinic += f; e[i].cap -= f; e[i^1].cap += f; if(dinic==flow) break; } } } return dinic; } int koala() { int dalao = 0; while( SPFA() ) dalao += DFS(s,inf); return dalao; } int main() { int x,y; n = read(); m = read(); s = 0; t = n+1; for(int i=1;i<=n;i++) { a[i] = read(); if(a[i]) add(s,i,1); else add(i,t,1); } while(m--) { x = read(); y = read(); add(x,y,1); add(y,x,1); } cout<<koala(); return 0; }

__EOF__

本文作者枫叶晴
本文链接https://www.cnblogs.com/maple276/p/12885592.html
关于博主:菜菜菜
版权声明:呃呃呃
声援博主:呐呐呐
posted @   maple276  阅读(108)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示