51Nod 1499 图(最小割)
来源:互联网 发布:freebsd和ubuntu 编辑:程序博客网 时间:2024/05/21 10:21
中文题。
说实话,确实没有想到这题可以用最小割来玩……
看了题解才知道,确实是有那么点像论文里面最大最小模型对应的最小割。
先说说具体做法吧。首先,对于所有的点i,我都向所有的其他点j连边,流量为|i-j|。然后,根据原图中的连通情况,对于任意两个点u,v,若存在边u->v,那么连边s->u和s->v流量都为|u-v|,反之则连边u->t和v->t流量都为|u-v|。最后的(ΣΣ|i-j|-mincut)/2就是最后结果。
下面,我就自己的理解说说为什么吧。首先,我们计算一个完全图的完美值,显然最大是ΣΣ|i-j|/2。但是实际上却不会这么完美,我们最后分成的两个集合的完美值会少很多,那么少的是哪些部分呢?对于A集合,少的是A中任意两个不相连的点的边权值,因为计算A的时候只会算相连的权值,所以少了不相连的权值;对于B集合,少的是B中任意两个相连的点的边权值,因为计算B的时候只会计算不相连的权值,所以少了相连的权值;另外还有就是A中的任意一个点和B中任意一个点连边的边权值,这个在完全图中会计算但是分成两部分之后少计算了。换句话说,完全图中是所有的边的权值都算了,但是给你的图不一定是完全图,所以有些边不能算,于是我们就要在完全图的基础上减去这些边。因此,我们就用之前说的方法建图,由于我们求的是最大的完美值,所以就要减去最小的边权,减去最少的这些没有计算到的边,所以对应最小割模型。
关于这个最小割,我再说说含义,如果最小割中有边s->i意味着i属于B集合,即i属于B集合,所以就要减去与i相连的点之间的权值;若最小割中有边i->t,意味着i属于A集合,即i属于A集合,所以就要减去与i不相连的点之间的权值;若最小割中有边i->j,意味着i和j不在同一个集合中,所以要减去他们两个产生的权值。又由于最小割中不存在s到t的路径,所以可以保证某一个点i不会即属于A集合也属于B集合。如此就可以确定算法的正确性。说的可能还不是很清楚,有问题欢迎提出。具体见代码:
#include<bits/stdc++.h>#define INF 0x3f3f3f3f#define M 4000010#define N 2010namespace ISAP{ int H[N],d[N],cur[N],pre[N],gap[N],Q[M]; struct Edge{short u,v,c;int n;} E[M]; int nv,flow,head,tail,cntE,f; void init(){cntE=0; memset(H,-1,sizeof(H));} void addedge(int u,int v,int c) { E[cntE]=Edge{u,v,c,H[u]}; H[u]=cntE++; E[cntE]=Edge{v,u,0,H[v]}; H[v]=cntE++; } void revbfs(int s,int t) { head=tail=0 ; memset(d,-1,sizeof(d)); memset(gap,0,sizeof(gap)); Q[tail++]=t;d[t]=0;gap[d[t]]=1; while (head!=tail) { int u=Q[head++]; for (int i=H[u];~i;i=E[i].n) { int v=E[i].v; if (~d[v]) continue; d[v]=d[u]+1; gap[d[v]]++; Q[tail++]=v; } } } int isap(int s,int t) { memcpy(cur,H,sizeof(cur)); nv=t; flow=0; revbfs(s,t); int u=pre[s]=s,i; while (d[s]<nv) { if (u==t) { f=INF; for (i=s;i!=t;i=E[cur[i]].v) if (f>E[cur[i]].c) f=E[cur[i]].c,u=i; flow += f; for (i=s;i!=t;i=E[cur[i]].v) E[cur[i]].c-=f,E[cur[i]^1].c+=f; } for (i=cur[u];~i;i=E[i].n) if (E[i].c&&d[u]==d[E[i].v]+1) break ; if (~i) cur[u]=i,pre[E[i].v]=u,u=E[i].v; else { if (0==--gap[d[u]]) break ; int minv=nv,v; for (int i=H[u];~i;i=E[i].n) { v=E[i].v; if (E[i].c&&minv>d[v]) minv=d[v],cur[u]=i; } d[u]=minv+1; gap[d[u]]++; u=pre[u]; } } return flow ; }}using namespace ISAP;bool vis[N][N];int n,m,sum,s,t;int main(){while(~scanf("%d%d",&n,&m)){ init(); sum=0; s=n+1; t=n+2;for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); vis[u][v]=vis[v][u]=1; addedge(s,u,abs(u-v)); addedge(s,v,abs(u-v)); sum+=abs(u-v)<<1; } for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { if (!vis[i][j]) { addedge(i,t,abs(i-j)); addedge(j,t,abs(i-j)); sum+=abs(i-j)<<1; } else vis[i][j]=vis[j][i]=0; addedge(i,j,abs(i-j)); addedge(j,i,abs(i-j)); } printf("%d\n",(sum-isap(s,t))/2);}return 0;}
- 51Nod 1499 图(最小割)
- 51Nod 1499 图(最小割+边在割的一边有收益建图)
- 51nod 1299 监狱逃离 树形dp/最小割
- (最小割模板)
- bzoj1412(最小割)
- 日程表(最小割)
- poj3469(最小割)
- poj 3155 二分+最小割求实型最小割(最大密集子图)
- poj 1815(最小割、割集)
- 51nod-距离之和最小(中位数)
- 51nod 最小集合
- 20141004 【 图论 -- 最小生成树(Dijkstra) 】 51nod 1212 . 无向图最小生成树
- 51nod 1212 无向图最小生成树(最小生成树)
- 无向图 最小割
- 无向图最小割
- 无向图最小割
- pku2914(求最小割)
- poj 3469(最小割)
- 技术解析:DAS、SAN和NAS三种存储方式
- POJ 1364 浅谈奇妙整数集合Z范围内超级源转化
- Linux compat_ioctl的由来
- atomic与nonatomic,assign,copy与retain,weak 和strong的区别
- 重建二叉树(前序和中序)
- 51Nod 1499 图(最小割)
- caffe添加新层windows
- 安卓ADB端口被占用/ADB无法使用解决办法
- 欢迎使用CSDN-markdown编辑器
- 逐一认识PorterDuff.Mode
- java定时任务实现的几种方式
- 欢迎使用CSDN-markdown编辑器
- Tablayoutdemo标题固定
- python学习(一)——基础