hdu 3657(最大点权独立集)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3657
思路我就不详细讲了,这位大牛讲的很清楚:http://blog.csdn.net/cold__v__moon/article/details/7924269
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define MAXN 55 5 #define MAXM 55*55 6 #define inf 1<<30 7 using namespace std; 8 struct Edge{ 9 int v,cap,next; 10 }edge[MAXM*11]; 11 12 int map[MAXN][MAXN]; 13 int head[MAXM]; 14 int pre[MAXM]; 15 int cur[MAXM]; 16 int level[MAXM]; 17 int gap[MAXM]; 18 int vs,vt,NV,n,m,k,NE; 19 bool mark[MAXN][MAXN]; 20 int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}}; 21 22 23 void Insert(int u,int v,int cap,int cc=0){ 24 edge[NE].cap=cap;edge[NE].v=v; 25 edge[NE].next=head[u];head[u]=NE++; 26 27 edge[NE].cap=cc;edge[NE].v=u; 28 edge[NE].next=head[v];head[v]=NE++; 29 } 30 31 32 //参数,源点,汇点 33 int SAP(int vs,int vt){ 34 memset(level,0,sizeof(level)); 35 memset(pre,-1,sizeof(pre)); 36 memset(gap,0,sizeof(gap)); 37 //cur[i]保存的是当前弧 38 for(int i=0;i<=NV;i++)cur[i]=head[i]; 39 int u=pre[vs]=vs;//源点的pre还是其本身 40 int maxflow=0,aug=-1; 41 gap[0]=NV; 42 while(level[vs]<NV){ 43 loop : 44 for(int &i=cur[u];i!=-1;i=edge[i].next){ 45 int v=edge[i].v;//v是u的后继 46 //寻找可行弧 47 if(edge[i].cap&&level[u]==level[v]+1){ 48 //aug表示增广路的可改进量 49 aug==-1?(aug=edge[i].cap):(aug=min(aug,edge[i].cap)); 50 pre[v]=u; 51 u=v; 52 //如果找到一条增广路 53 if(v==vt){ 54 maxflow+=aug;//更新最大流; 55 //路径回溯更新残留网络 56 for(u=pre[v];v!=vs;v=u,u=pre[u]){ 57 //前向弧容量减少,反向弧容量增加 58 edge[cur[u]].cap-=aug; 59 edge[cur[u]^1].cap+=aug; 60 } 61 aug=-1; 62 } 63 goto loop; 64 } 65 } 66 int minlevel=NV; 67 //寻找与当前点相连接的点中最小的距离标号(重标号) 68 for(int i=head[u];i!=-1;i=edge[i].next){ 69 int v=edge[i].v; 70 if(edge[i].cap&&minlevel>level[v]){ 71 cur[u]=i;//保存弧 72 minlevel=level[v]; 73 } 74 } 75 if((--gap[level[u]])==0)break;//更新gap数组后如果出现断层,则直接退出。 76 level[u]=minlevel+1;//重标号 77 gap[level[u]]++;//距离标号为level[u]的点的个数+1; 78 u=pre[u];//转当前点的前驱节点继续寻找可行弧 79 } 80 return maxflow; 81 } 82 83 84 int main(){ 85 int u,v,sum; 86 while(~scanf("%d%d%d",&n,&m,&k)){ 87 vs=0,vt=n*m+1,NV=vt+1,sum=0,NE=0; 88 memset(mark,false,sizeof(mark)); 89 memset(head,-1,sizeof(head)); 90 for(int i=1;i<=n;i++){ 91 for(int j=1;j<=m;j++){ 92 scanf("%d",&map[i][j]); 93 sum+=map[i][j]; 94 } 95 } 96 97 for(int i=1;i<=k;i++){ 98 scanf("%d%d",&u,&v); 99 mark[u][v]=true; 100 } 101 for(int i=1;i<=n;i++){ 102 for(int j=1;j<=m;j++){ 103 if((i+j)%2==1){ 104 mark[i][j]?Insert(vs,(i-1)*m+j,inf):Insert(vs,(i-1)*m+j,map[i][j]); 105 for(int l=0;l<4;l++){ 106 int xx=i+dir[l][0],yy=j+dir[l][1]; 107 if(xx>=1&&xx<=n&&yy>=1&&yy<=m){ 108 Insert((i-1)*m+j,(xx-1)*m+yy,(map[i][j]&map[xx][yy])*2); 109 } 110 } 111 }else{ 112 mark[i][j]?Insert((i-1)*m+j,vt,inf):Insert((i-1)*m+j,vt,map[i][j]); 113 } 114 } 115 } 116 printf("%d\n",sum-SAP(vs,vt)); 117 } 118 return 0; 119 } 120 121 122