zoukankan      html  css  js  c++  java
  • 二分图带权最大独立集 网络流解决 hdu 1569

    方格取数(2)

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 3663    Accepted Submission(s): 1148

    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
     
    Author
    ailyanlu
     
    Source
     
    Recommend
    8600
     
     
     
    思路:

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

    最小割=最大流

    最小点权覆盖集=最小割

    根据奇偶建立二分图,

    if(i+j)%2==0 源点和该点连接,权值为该点的点权,

    if(i+j)%2==1 该点和汇点连接,权值为该点的点权,

    之后若i+j为偶数的点和i+j为奇数的点之间相邻,那么就连一条从为偶数的点到为奇数的点的边,权值为无穷大

    之后  所有权值-最大流 即可

    #include <stdio.h>
    #include <string.h>
    #define VM 2555
    #define EM 2055000
    #define inf 0x3f3f3f3f
    struct Edge
    {
        int frm,to,cap,next;
    }edge[EM];
    
    int head[VM],dep[VM],ep;     //dep为点的层次
    void addedge (int cu,int cv,int cw)  //第一条边下标必须为偶数
    {
        edge[ep].frm = cu;
        edge[ep].to = cv;
        edge[ep].cap = cw;
        edge[ep].next = head[cu];
        head[cu] = ep;
        ep ++;
        edge[ep].frm = cv;
        edge[ep].to = cu;
        edge[ep].cap = 0;
        edge[ep].next = head[cv];
        head[cv] = ep;
        ep ++;
    }
    
    int BFS (int src,int des)     //求出层次图
    {
        int que[VM],i,front = 0,rear = 0;
        memset (dep,-1,sizeof(dep));
        que[rear++] = src;
        dep[src] = 0;
        while (front != rear)
        {
            int u = que[front++];
            front = front%VM;
            for (i = head[u];i != -1;i = edge[i].next)
            {
                int v = edge[i].to;
                if (edge[i].cap > 0&&dep[v] == -1) //容量大于0&&未在dep中
                {
                    dep[v] = dep[u] + 1;        //建立层次图
                    que[rear ++] = v;
                    rear = rear % VM;
                    if (v == des)  //找到汇点 返回
                        return 1;
                }
            }
        }
        return 0;
    }
    int dinic (int src,int des)
    {
        int i,res = 0,top;
        int stack[VM];    //stack为栈,存储当前增广路
        int cur[VM];        //存储当前点的后继 跟head是一样的
        while (BFS(src,des))   //if BFS找到增广路
        {
            memcpy (cur,head,sizeof (head));
            int u = src;       //u为当前结点
            top = 0;
            while (1)
            {
                if (u == des)     //增广路已全部进栈
                {
                    int min = inf,loc ;
                    for (i = 0;i < top;i ++)       //找最小的增广跟并loc记录其在stack中位置
                        if (min > edge[stack[i]].cap)  //以便退回该边继续DFS
                        {
                            min = edge[stack[i]].cap;
                            loc = i;
                        }
                    for (i = 0;i < top;i ++)   //偶数^1 相当加1 奇数^1相当减1 当正向边 = 0&&路径不合适时,正加负减
                    {                           //偶数是正向边,奇数是负向边,边从0开始
                        edge[stack[i]].cap -= min;
                        edge[stack[i]^1].cap += min;
                    }                              //将增广路中的所有边修改
                    res += min;
                    top = loc;
                    u = edge[stack[top]].frm;         //当前结点修改为最小边的起点
                }
                for (i = cur[u];i != -1;cur[u] = i = edge[i].next)   //找到当前结点对应的下一条边
                    if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])//不满足条件时,修改cur值(去掉不合适的占)eg:1-->2 1-->3 1-->4 有边 但只有
                        break;                                  // 1-->4 这条边满足条件 就把1到2、3的边给去掉
                if (cur[u] != -1)            //当前结点的下一条边存在
                {
                    stack[top ++] = cur[u];   //把该边放入栈中
                    u = edge[cur[u]].to;         //再从下个点开始找
                }
                else
                {
                    if (top == 0)        //当前结点无未遍历的下一条边且栈空,DFS找不到下一条增广路
                        break;
                    dep[u] = -1;            //当前结点不在增广路中,剔除该点
                    u = edge[stack[--top]].frm; //退栈 回朔,继续查找
                }
            }
        }
        return res;
    }
    
    int dir[4][2]={0,1,0,-1,1,0,-1,0};
    int x,y;
    int main ()///坐标从0或1开始均可  注意别忘记下面的2个初始化
    {
        int m,n;
        int src,des;
        int sum=0;
        while (scanf ("%d %d",&m,&n)!=EOF)
        {
            sum=0;
            ep = 0;//边的初始化
            src =n*m;
            des =m*n+1;
            memset (head,-1,sizeof(head));///这里初始化
            for(int i=0;i<m;i++)
                for(int j=0;j<n;j++)
                {
                    int mid;
                    scanf("%d",&mid);
                    sum+=mid;
                    //printf("%d
    ",i*m+j);
                    if((i+j)%2==0) addedge(src,i*n+j,mid);
                    else addedge(i*n+j,des,mid);
                }
            for(int i=0;i<m;i++)
            {
                for(int j=0;j<n;j++)
                {
                    for(int k=0;k<4;k++)
                    {
                       x=i+dir[k][0];
                       y=j+dir[k][1];
                       if(x>=0&&x<m&&y>=0&&y<n)
                       {
                           if(((x+y)%2)!=((i+j)%2))
                           {
                               if((x+y)%2==1)
                               addedge(i*n+j,x*n+y,inf);
                               else addedge(x*n+y,i*n+j,inf);
                           }
                       }
                    }
                }
            }
           // printf("sum=%d
    ",sum);
            int ans = dinic (src,des);
            printf ("%d
    ",sum-ans);
        }
        return 0;
    }
    


     

  • 相关阅读:
    eclipse里maven项目An error occurred while filtering resources解决办法
    python中分页使用
    es学习
    cmdb资产管理2
    saltstack安装使用
    Django Rest Framework
    免交互批量分发公钥的实现
    单链表复制早已难不到你,但若我们再加个指针...
    面试 16:栈的压入压出队列(剑指 Offer 第 22 题)
    面试 15:顺时针从外往里打印数字(剑指 Offer 第 20 题)
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3283302.html
Copyright © 2011-2022 走看看