[bzoj4874]筐子放球
来源:互联网 发布:java 接口开发 编辑:程序博客网 时间:2024/05/01 20:02
题目描述
小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目:
有 n 个球,用整数 1 到 n 编号。还有 m 个筐子,用整数1到m编号。
每个球只能放进特定的两个筐子之一,第 i 个球可以放进的筐子记为 Ai 和 Bi 。
每个球都必须放进一个筐子中。
如果一个筐子内有奇数个球,那么我们称这样的筐子为半空的。
求半空的筐子最少有多少个。
小N看到题目后瞬间没了思路,站在旁边看热闹的小I嘿嘿一笑:”水题!”
然后三言两语道出了一个多项式算法。
小N瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
“不对!这个问题显然是NP完全问题,你算法肯定有错!”
小I浅笑:”所以,等我领图灵奖吧!”
小O只会出题不会做题,所以找到了你–请你对这个问题进行探究,并写一个程序解决此题。
题解
我们把筐子看做点,球看做边,得到一副无向图。
对于一个联通块,如果有偶数条边,可以让这个联通块不产生任何半空点。
假设一种方案使得半空点存在,由于总数为偶数,一定有另一个半空点也存在。更大的,半空点数量一定是偶数。我们找到这两个半空点之间的一条路径,显然可以通过调整使得半空点被一条边连接,然后改变这条边的去向,可以使得两个半空点均被消除。这样任意次可以消除图中所有半空点。
如果一个联通块有奇数条边,那么无论如何都会存在一个半空点。
假如该联通块就是一颗树,每个点都根据到儿子边的去向,来决定到父亲边的去向,来让这个点不是半空点,最后根节点无法这样做,因此会有一个半空点。
如果不是一颗树,可以造出一颗生成树,然后删去任意一条非树边,剩余还是联通图且边数为偶数,根据之前的证明可以不存在半空点,加上这条被删去的边后会存在一个半空点。
因此只要统计奇数条边的联通块个数就是答案。
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=200000+10;int h[maxn],go[maxn*2],next[maxn*2];bool bz[maxn],pd[maxn];int i,j,k,l,t,n,m,tot,ans;void add(int x,int y){ go[++tot]=y; next[tot]=h[x]; h[x]=tot;}void dfs(int x){ pd[x]=1; int t=h[x]; while (t){ if (!bz[(t+1)/2]){ bz[(t+1)/2]=1; l++; if (!pd[go[t]]) dfs(go[t]); } t=next[t]; }}int main(){ scanf("%d%d",&n,&m); fo(i,1,n){ scanf("%d%d",&j,&k); add(j,k);add(k,j); } fo(i,1,m) if (!pd[i]){ l=0; dfs(i); if (l%2==1) ans++; } printf("%d\n",ans);}
- [bzoj4874]筐子放球
- BZOJ4874:筐子放球
- [BZOJ4874]筐子放球
- 连通块——BZOJ4874 筐子放球
- 4874: 筐子放球
- bzoj 4874: 筐子放球 并查集
- [特殊的一般图最大匹配] BZOJ 4874 筐子放球
- 【笔记】放球模型
- 排列组合-放球模型
- 放球模型
- nod_1418_放球游戏
- 概率之放球
- 放球问题
- 盒子放球问题
- 【证明】放球问题
- 放球问题
- 放
- 放
- Maven依赖Scope标签用法
- 第三天 asp
- 网络端口号的类型
- 《git常用命令总结》
- java基础--5.集合-3.集合中的数据结构
- [bzoj4874]筐子放球
- ArrayList动态数组
- 909422229_Sping+Struts2+Mybatis整合步骤
- java加密与解密的艺术(三)——非对称密码体制
- Call Screening(来电过滤) on Android N
- C#多线程编程Task任务
- DBscan简单记录
- bzoj2097[Usaco2010 Dec]Exercise 奶牛健美操
- 计蒜客 爬楼梯 (dp)