【网络流第四弹】最大点权独立集 ——HDU 1565 方格取数(1)

来源:互联网 发布:淘宝支付宝账户 编辑:程序博客网 时间:2024/06/07 17:14

题目:点击打开链接

网络流学习的下一步,最大点权独立集。多和最小点权覆盖集放到一起使用。分别求图中不相邻的点权最大/或者边中至少有一点在集合中,求最小总权值的问题。

公式:

最大点权独立集=总权值-最小点权覆盖集。

最小点权覆盖集=图的最小割值=最大流。和普通网络流一样,可以使用ISAP,EK,DINIC等多种方法。

建图:

多采用奇偶建立二分图的方法。建边时脑子一定要清楚。相邻点要染不同的颜色,源点为0,汇点为最后的那个点。染色方法基本上是判断if(边+边)%2==0源点与其连接,反之汇点与其连接。如果两点相邻的话,连接值为INF,无穷大。

脑子一定要清醒。。wa了若干次,用的是最快的sap.

#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=2000; 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(cin>>pt)     {         int tmp;          init();          n=2000;           m=10000;           int sum=0; //最大点权独立集=总权值-最小点权覆盖集=总权值-最小割          int st=0;  //start point          int ed=(pt*pt)+1;          for(int i=1;i<=pt;i++)          {              for(int j=1;j<=pt;j++)              {                  scanf("%d",&tmp);                  sum+=tmp;                  if((i+j)%2==0)  //偶数序号点                {                    insert1(st,(i-1)*pt+j,tmp);                    if(i>1)                    insert1((i-1)*pt+j,(i-2)*pt+j,INF);                    if(j>1)                    insert1((i-1)*pt+j,(i-1)*pt+j-1,INF);  //顺序一定不能错                     if(i<pt)                    insert1((i-1)*pt+j,(i)*pt+j,INF);                    if(j<pt)                    insert1((i-1)*pt+j,(i-1)*pt+j+1,INF);                }                else                    insert1((i-1)*pt+j,ed,tmp);                              }                      }          int res=sap(st,ed);          cout<<sum-res<<endl;      }      return 0; }


原创粉丝点击