SPOJ 839 Optimal Marks
来源:互联网 发布:ubuntu on windows 编辑:程序博客网 时间:2024/06/05 16:30
最小割的经典题。
这题的具体做法就不说了,网上一大堆说的很好的。
我说一下怎么理解这题里的最小割吧。
一条边如果在最小割之中,你可以理解成让这条边左边的点与右边的点矛盾所需要的代价。
下面的讨论都是限定在某一个二进制位上:
如果能让所有的点都在一个集合中那是最好的,因为所有XOR的结果都是0。
但这明显是不可能的,因为根据题目所给的已知数字,已经分成了两部分了,即这个二进制位是0还是1。
默认左边集合是1,右边集合是0。
如果一个数字只需要和左边集合XOR,那么它显然只要为1就可以了,只和右边的话显然为0。
但是有些数字是和左右都需要XOR,这里就需要做出和左边相反还是右边相反的选择了,自己画一个图,如果它需要和左边两个点XOR,右边一个点XOR,那么这个最小割显然是右边那条边。
那么就可以理解最小割了。即和最少的人相反。
再扩大点范围,就是让左边集合与右边集合相交界处的权值最小。这也和最小割的原本定义类似。
然后这题的点数好像很坑,反正记得开大点。
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <queue>using namespace std;const int MAXN = 50100;const int MAXM = 50000;const int INF = 0x3f3f3f3f;struct Edge{ int to,cap,flow,nex; Edge() {} Edge(int to,int cap,int flow,int nex):to(to),cap(cap),flow(flow),nex(nex) {}} edge[MAXM];int tol,dis[MAXN],n,m,k,head[MAXN],x[MAXN],y[MAXN],num[MAXN],ans[MAXN];bool vis[MAXN];void addedge(int u,int v,int cap,int rw=0){ edge[tol]=Edge(v,cap,0,head[u]); head[u]=tol++; edge[tol]=Edge(u,rw,0,head[v]); head[v]=tol++;}bool bfs(int s,int t){ queue<int> que; que.push(s); memset(dis,-1,sizeof dis); dis[s]=0; while (!que.empty()) { int u=que.front(); que.pop(); for (int i=head[u]; ~i; i=edge[i].nex) { int v=edge[i].to; if (dis[v]==-1 && edge[i].cap>edge[i].flow) { dis[v] = dis[u]+1; if (v==t) return true; que.push(v); } } } return false;}int dfs(int u,int t,int cap){ if (u==t) return cap; int flow=0,f; for (int i=head[u]; ~i; i=edge[i].nex) { int v=edge[i].to; if (dis[v]==dis[u]+1 && edge[i].cap>edge[i].flow) { f=dfs(v,t,min(cap-flow,edge[i].cap-edge[i].flow)); edge[i].flow += f; edge[i^1].flow -=f; flow += f; if (flow == cap) break; } } if (!flow ) dis[u]=-1; return flow;}int dicnic(int s,int t){ int flow=0,f; while (bfs(s,t)) while ((f=dfs(s,t,INF))>0) flow += f; return flow;}void dfs2(int u,int ad){ vis[u]=true; for (int i=head[u]; ~i; i=edge[i].nex) { int v=edge[i].to; if (!vis[v] && edge[i].cap>edge[i].flow) { ans[v] += ad; dfs2(v,ad); } }}int main(){ int t; cin>>t; while (t--) { memset(ans,0,sizeof ans); memset(num,-1,sizeof num); scanf("%d%d",&n,&m); for (int i=1; i<=m; i++) scanf("%d%d",&x[i],&y[i]); scanf("%d",&k); for (int i=1; i<=k; i++) { int m; scanf("%d",&m); scanf("%d",&num[m]); } int ad=1; while (1) { memset(vis,0,sizeof vis); memset(head,-1,sizeof head); tol=0; bool flag=false; for (int i=1; i<=n; i++) { if (num[i]==-1) continue; if (num[i]>=1) flag=true; if (num[i]&1) addedge(0,i,INF); else addedge(i,n+1,INF); num[i]>>=1; } for (int i=1; i<=m; i++) addedge(x[i],y[i],1,1); if (!flag) break; dicnic(0,n+1); dfs2(0,ad); ad<<=1; } for (int i=1; i<=n; i++) { printf("%d\n",ans[i]); } } return 0;}
阅读全文
0 0
- spoj 839(Optimal Marks)
- spoj 839 Optimal Marks
- SPOJ 839 Optimal Marks
- SPOJ 839 Optimal Marks
- 2400: Spoj 839 Optimal Marks
- BZOJ2400 Spoj 839 Optimal Marks
- BZOJ2400: Spoj 839 Optimal Marks
- SPOJ 839 Optimal Marks 最小割
- 【SPOJ】839 Optimal Marks 最小割
- bzoj 2400: Spoj 839 Optimal Marks
- 2400: Spoj 839 Optimal Marks 最小割
- 【bzoj2400】Spoj 839 Optimal Marks 最小割
- SPOJ 839 Optimal Marks 学习简记
- BZOJ 2400 Spoj 839 Optimal Marks
- bzoj 2400: Spoj 839 Optimal Marks
- [bzoj2400]Spoj 839 Optimal Marks 最小割
- SPOJ Optimal Marks 最小割
- SPOJ 839 Optimal Marks 最小割 经典 按位建图
- jsp内省EL
- bzoj1095 线段树括号序列
- ImageIcon & Image
- linux--sudo su命令
- 冒泡排序法
- SPOJ 839 Optimal Marks
- 02-线性结构2 一元多项式的乘法与加法运算(20 分)
- SpringMVC开发一:SpringMVC的maven搭建及配置
- Python List
- Linux进阶之 which 命令
- DB2中load异常中断导致表状态异常处理方法
- RCNN
- java中的jar包是写好的类那么为什么查看时需要导入源码
- WebDriver HTML5