• HDU 1569


    嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题。

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569

    Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

    Problem Description
    给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
    从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
    Input
    包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
    Output
    对于每个测试实例,输出可能取得的最大的和
    Sample Input
    3 3
    75 15 21
    75 15 28
    34 70 5
    Sample Output
    188
     
    题目思路:
    首先我们把所有相邻的格子都连一条边,那么我们的问题就转化成:
    这张图上,我们要取得最大的点权(这里的点就相当于带权的格子)集,并且这个点集里的任意两个点之间都没有边(即任意两点不相邻)。
    这个即最大点权独立集问题,根据上面的讲解,转化成最小点权覆盖集进行求解。
    于是依样画葫芦,先求出所有点权和,记为sum(Wv);
    每个相邻的两个格子建边,cap设为INF,方向为从(i+j)是奇数的点到(i+j)是偶数的点;
    建立超级源点s,连到所有(i+j)为奇数的点,方向为s出发,cap设为点权;
    建立超级汇点t,连到所有(i+j)为偶数的点,方向为到达t,cap设为点权;
    这样的话,这个图中,m行n列的方格阵,|V| = mn+2,|E| = m(n-1)+n(m-1) = 2mn-m-n;
    我们做最大流求s-t最小割cut.w,便可以得到答案为sum(Wv) - cut.w。
      1 #include<cstdio>
      2 #include<cstring>
      3 #include<vector>
      4 #include<queue>
      5 #define MAX 53*53
      6 #define INF 0x3f3f3f3f
      7 using namespace std;
      8 int m,n,map[53][53],sum; 
      9 int d[4][2]={{0,+1},{+1,0},{0,-1},{-1,0}};
     10 struct Edge{
     11     int u,v,c,f;
     12 };
     13 struct Dinic
     14 {
     15     int s,t;
     16     vector<Edge> E;
     17     vector<int> G[MAX];
     18     bool vis[MAX];
     19     int lev[MAX];
     20     int cur[MAX];
     21     void init(int l,int r) 
     22     {
     23         E.clear();
     24         for(int i=l;i<=r;i++) G[i].clear();
     25     }
     26     void addedge(int from,int to,int cap)
     27     {
     28         E.push_back((Edge){from,to,cap,0});
     29         E.push_back((Edge){to,from,0,0});
     30         G[from].push_back(E.size()-2);
     31         G[to].push_back(E.size()-1);
     32     }
     33     bool bfs()
     34     {
     35         memset(vis,0,sizeof(vis));
     36         queue<int> q;
     37         q.push(s);
     38         lev[s]=0;
     39         vis[s]=1;
     40         while(!q.empty())
     41         {
     42             int now=q.front(); q.pop();
     43             for(int i=0,_size=G[now].size();i<_size;i++)
     44             {
     45                 Edge edge=E[G[now][i]];
     46                 int nex=edge.v;
     47                 if(!vis[nex] && edge.c>edge.f)
     48                 {
     49                     lev[nex]=lev[now]+1;
     50                     q.push(nex);
     51                     vis[nex]=1;
     52                 }
     53             }
     54         }
     55         return vis[t];
     56     }
     57     int dfs(int now,int aug)
     58     {
     59         if(now==t || aug==0) return aug;
     60         int flow=0,f;
     61         for(int& i=cur[now],_size=G[now].size();i<_size;i++)
     62         {
     63             Edge& edge=E[G[now][i]];
     64             int nex=edge.v;
     65             if(lev[now]+1 == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>0)
     66             {
     67                 edge.f+=f;
     68                 E[G[now][i]^1].f-=f;
     69                 flow+=f;
     70                 aug-=f;
     71                 if(!aug) break;
     72             }
     73         }
     74         return flow;
     75     }
     76     int maxflow()
     77     {
     78         int flow=0;
     79         while(bfs())
     80         {
     81             memset(cur,0,sizeof(cur));
     82             flow+=dfs(s,INF);
     83         }
     84         return flow;
     85     }
     86 }dinic;
     87 int inmap(int i,int j)
     88 {
     89     if(1<=i && i<=m && 1<=j && j<=n) return (i-1)*n+j;
     90     else return 0;
     91 }
     92 int main()
     93 {
     94     while(scanf("%d%d",&m,&n)!=EOF)//m行n列 
     95     {
     96         dinic.init(0,m*n+1);
     97         sum=0;
     98         dinic.s=0, dinic.t=m*n+1; 
     99         for(int i=1;i<=m;i++)
    100         {
    101             for(int j=1;j<=n;j++)
    102             {
    103                 scanf("%d",&map[i][j]);
    104                 sum+=map[i][j];
    105                 int id=(i-1)*n+j;
    106                 if((i+j)%2)
    107                 {
    108                     for(int k=0,_id;k<4;k++) if(_id=inmap(i+d[k][0],j+d[k][1])) dinic.addedge(id,_id,INF);
    109                     dinic.addedge(dinic.s,id,map[i][j]);
    110                 }
    111                 else dinic.addedge(id,dinic.t,map[i][j]);
    112             }
    113         }
    114         printf("%d
    ",sum-dinic.maxflow());
    115     }
    116 }
  • 相关阅读:
    web测试知识点整理
    LINUX系统、磁盘与进程的相关命令
    压缩与解压
    LINUX基本操作命令
    linux命令管道工作原理与使用方法
    C#根据path文件地址进行下载
    C#向Word文档中的书签赋值
    网站发布
    乱码转换
    获取新增的数据ID
  • 原文地址:https://www.cnblogs.com/dilthey/p/7401563.html
Copyright © 2020-2023  润新知