【网络流第五弹】最大点权独立集 ——HDU 1569 方格取数(2)

题目:点击打开链接

和上一道基本一样,依然是最大点权独立集的问题,毫无变化。注意一下数据变大了,所以EK就不行了,SAP或者DINIC。

#include <iostream>
#include <cstring>
#include <string>
#include <iomanip>
using namespace std;

typedef  struct {int v,next,val;} edge;
const int INF=0x3F3F3F3F;
 const int MAXN=4000;
 const int MAXM=50000;
 edge e[MAXM];
 int p[MAXN],eid;
 inline void init(){memset(p,-1,sizeof(p));eid=0;}
 
 //有向
 inline void insert1(int from,int to,int val)
 {
     e[eid].v=to;
     e[eid].val=val;
     e[eid].next=p[from];
     p[from]=eid++;
     swap(from,to);
     e[eid].v=to;
     e[eid].val=0;
     e[eid].next=p[from];
     p[from]=eid++;
 }
 
 //无向
 inline void insert2(int from,int to,int val)
 {
     e[eid].v=to;
     e[eid].val=val;
     e[eid].next=p[from];
     p[from]=eid++;
     swap(from,to);
     e[eid].v=to;
     e[eid].val=val;
     e[eid].next=p[from];
     p[from]=eid++;
 }
 int n,m;//n为点数 m为边数
 int h[MAXN];
 int gap[MAXN];
 int source,sink;
 inline int dfs(int pos,int cost)
 {
     if (pos==sink)
     {
         return cost;
     }
     int j,minh=n-1,lv=cost,d;
     for (j=p[pos];j!=-1;j=e[j].next)
     {
         int v=e[j].v,val=e[j].val;
         if(val>0)
         {
             if (h[v]+1==h[pos])
             {
                 if (lv<e[j].val) d=lv;
                 else d=e[j].val;
                 
                 d=dfs(v,d);
                 e[j].val-=d;
                 e[j^1].val+=d;
                 lv-=d;
                 if (h[source]>=n) return cost-lv;
                 if (lv==0) break;
             }
             if (h[v]<minh)    minh=h[v];
         }
     }
     if (lv==cost)
     {
         --gap[h[pos]];
         if (gap[h[pos]]==0) h[source]=n;
         h[pos]=minh+1;
         ++gap[h[pos]];
     }
     return cost-lv;
 }
 int sap(int st,int ed)
 {
     source=st;
     sink=ed;
     int ret=0;
     memset(gap,0,sizeof(gap));
     memset(h,0,sizeof(h));
     gap[st]=n;
     while (h[st]<n)
     {
         ret+=dfs(st,INF);
     }
     return ret;
 }
 int main()
 {
 	 int pt,ma;
     while(scanf("%d%d",&pt,&ma)!=EOF)
	 {
	 	int tmp;
		  init();
		  n=3000;
 		  m=20000;
 		  int sum=0; //最大点权独立集=总权值-最小点权覆盖集=总权值-最小割
	      int st=0;  //start point
	      int ed=(pt*ma)+1;
	      for(int i=1;i<=pt;i++)
	      {
      		for(int j=1;j<=ma;j++)
      		{
		      	scanf("%d",&tmp);
		      	sum+=tmp;
		      	if((i+j)%2==0)  //偶数序号点
				{
					insert1(st,(i-1)*ma+j,tmp);
					if(i>1)
					insert1((i-1)*ma+j,(i-2)*ma+j,INF);
					if(j>1)
					insert1((i-1)*ma+j,(i-1)*ma+j-1,INF);  //顺序一定不能错 
					if(i<pt)
					insert1((i-1)*ma+j,(i)*ma+j,INF);
					if(j<ma)
					insert1((i-1)*ma+j,(i-1)*ma+j+1,INF);
				}
				else
					insert1((i-1)*ma+j,ed,tmp);
		      	
	        }
	        
      	}
      	int res=sap(st,ed);
      	printf("%d\n",sum-res);
 	 } 
     return 0;
 }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值