HDU1569 方格取数(2)(最大点权独立集 + 最小点权覆盖集 = 总权和)
来源:互联网 发布:php导出excel乱码问题 编辑:程序博客网 时间:2024/05/18 04:00
给出一个 N * M 的矩阵,每个格放着一个非负数,要求选出一些数,使他们的和最大,要求是有相邻边的格子里的数不能同时选。
先说,我压根没想过这事网络流……因为方格取数(1)是个状态压缩……
看了题解,才明白的:
这个题由于数据范围较大,所以状态压缩过不去,需要用网络流,我重复一遍人家的建图:
我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有:
最大点权独立集 + 最小点权覆盖集 = 总点权和,
这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图,
1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一条边,权值为该黑色点的权值,
2,从白色的点向汇点连一条边,权值为该白色点的权值,
3,然后,对于每一对相邻的黑白点,从黑点向白点连一条边,权值为无穷大。
最后求最小割(最大流),即为最小点权覆盖集。
因为我们求出的最小割集一定是从那些相邻的黑白点之间的边(也就是不能用的边,因为相邻的数不能同时选)中选出来的,且是最小代价,也就是说从方格中拿掉的数之和尽量小,那么剩下的数之和一定是最大的。
我只能说,神奇的网络流!!!!Orz!!!!
代码:
#include<cstdio>#include<cstring>#include<queue>#include<cmath>#define find_min(a,b) a<b?a:busing namespace std;const int N = 2550;const int MAX = 100000;struct Edge{ int s,e,v; int next;}edge[20*N];int dir[4][2]={-1,0, 1,0, 0,-1, 0,1};int n,m,e_num,head[N],d[N],sp,tp;void AddEdge(int a,int b,int c){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c; edge[e_num].next=head[a]; head[a]=e_num++; edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=0; edge[e_num].next=head[b]; head[b]=e_num++;}int judge(int i,int j,int k){ int ii=i+dir[k][0]; int jj=j+dir[k][1]; if(ii>=1 && ii<=n && jj>=1 && jj<=m)return 1; return 0;}int bfs(){queue <int> q;memset(d,-1,sizeof(d));d[sp]=0;q.push(sp);while(!q.empty()){int cur=q.front();q.pop();for(int i=head[cur];i!=-1;i=edge[i].next){int u=edge[i].e;if(d[u]==-1 && edge[i].v>0){d[u]=d[cur]+1;q.push(u);}}}return d[tp] != -1;}int dfs(int a,int b){int r=0;if(a==tp)return b;for(int i=head[a];i!=-1 && r<b;i=edge[i].next){int u=edge[i].e;if(edge[i].v>0 && d[u]==d[a]+1){int x=find_min(edge[i].v,b-r);x=dfs(u,x);r+=x;edge[i].v-=x;edge[i^1].v+=x;}}if(!r)d[a]=-2;return r;}int dinic(int sp,int tp){int total=0,t;while(bfs()){while(t=dfs(sp,MAX))total+=t;}return total;}int main(){ int i,j,k,a; while(~scanf("%d%d",&n,&m)) { int sum=0; e_num=0; memset(head,-1,sizeof(head)); sp=0; tp=n*m+1; for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ scanf("%d",&a); sum+=a; int x=(i-1)*m+j; if((i+j)%2==0){ AddEdge(sp,x,a); for(k=0;k<4;k++){ if(judge(i,j,k)==1){//不出界 int y=(i+dir[k][0]-1)*m+(j+dir[k][1]); AddEdge(x,y,MAX);//这里要注意边的方向,是黑点向白点连边 } } } else{ AddEdge(x,tp,a); for(k=0;k<4;k++){ if(judge(i,j,k)==1){//不出界 int y=(i+dir[k][0]-1)*m+(j+dir[k][1]); AddEdge(y,x,MAX);//注意边的方向,和上面的是相反的 } } } } } int max_flow=dinic(sp,tp); printf("%d\n",sum-max_flow); } return 0;}
- HDU1569 方格取数(2)(最大点权独立集 + 最小点权覆盖集 = 总权和)
- [hdu1569]方格取数(2) 最大点权独立集
- hdu1569 方格取数 求最大点权独立集
- hdu1569 方格取数(2) 二分图最大点权独立集
- HDU 1565 方格取数(1)(最大独立点权覆盖 | 最小割)
- 方格取数(2)(最大点权独立集)
- hdoj 1569 方格取数(2) 【最小割】 【最大点权独立集】
- hdu 1565 方格取数(1)(最小割,最大点权独立集)
- [网络流][最大点权独立集] 方格取数
- 【最大点权独立集】【HDU1565】【方格取数】
- 【codevs1907】方格取数3 最大点权独立集
- 【BZOJ 1475】方格取数 最大点权独立集
- BZOJ 1475: 方格取数 最大点权独立集
- loj6007「网络流 24 题」方格取数(最大点权独立集+最小割)
- hdu 1569 方格取数(2)--最大点权独立集-->最大流
- 最小点权覆盖=最大点权独立集
- hdu 1569 方格取数(2) 网络流--最大点权独立集
- HDU 1569 方格取数(2)(最大点权独立集)
- linux平台 oracle 数据库 安装文档
- 14.64.3 行过滤及排序键 Table row filer and sort key
- HTML5设计原理 Jeremy Keith在 Fronteers 2010 上的主题演讲
- Oracle 10g Scheduler 特性
- struts2中用interceptor实现权限控制
- HDU1569 方格取数(2)(最大点权独立集 + 最小点权覆盖集 = 总权和)
- Android Gallery3D源码分析
- 每日学习笔记(20)
- Oracle Merge Into 的用法详解实例
- Oracle 物化视图
- Android 多点触摸
- Jar 转 EXE 可以脱离 java 环境 jar to exe和Jsmooth 的使用
- 【总结】关于shell执行,export 和 source
- jQuery实现多选下来框(multiple select)