您的位置:首页 > 理论基础 > 计算机网络

Hdu 1569 方格取数(2) (网络流最大点权独立集)

2013-03-03 21:19 531 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569

思路:首先黑白染色,源点到黑点连条边,值为格子数值,然后白色点到汇点也连条这样的边,然后每个黑点对与其相连的白点连条无穷大的边,然后求个最小割,答案就是所有格子数值和减去这个最小割。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int INF = 0x6fffffff ;   //权值上限
const int MAXPT = 3000;           //顶点数上限
const int MAXEG = 50000 ; //边数上限
const int MAXQUE = 10005 ;	      //队列长度

/*
    s = 1 ; // 源点
    t = n ; // 汇点
*/
class MNF_SAP
{
private:

    //int m,n;
    int s,t;
    int dis[MAXPT];   //距离标号
    int pre[MAXPT];   //前置顶点
    int flow[MAXPT];  //到当前点为止,所有弧的最小值
    int curedge[MAXPT];   //当前弧cur
    int cnt[MAXPT];   //k标号出现次数
    int queue[MAXQUE],front,rear;
    bool vis[MAXPT];

    void BFS ()
    {
        int i,u;
        memset(vis,false,sizeof(vis));
        front=rear=0;
        dis[t]=0;
        vis[t]=true;
        queue[++rear]=t;
        while (front!=rear)
        {
            u=queue[(++front)%MAXQUE];
            for (i=head[u];i!=0;i=edges[i].next)
                if (vis[edges[i].v]==false && !edges[i].cap)
                {
                    dis[edges[i].v]=dis[u]+1;
                    vis[edges[i].v]=true;
                    queue[(++rear)%MAXQUE]=edges[i].v;
                }
        }
		for (i=1;i<=n;i++)
			cnt[dis[i]]++;
    }
public:

    struct Node
    {
        int v,cap,next;
		Node(){}
		Node (int _v,int _cap,int _next)
		{
			v=_v;
			cap=_cap;
			next=_next;
		}
    }edges[MAXEG];
    int n;      //总节点数
	int e;
    int head[MAXPT];
//    MNF_SAP(){}
//    ~MNF_SAP(){}

	void init (int temp)    //算法初始化
	{
		n=temp;
		e=2;
		memset (head,0,sizeof(head));
	}

	void Add (int u,int v,int cap)   //始,终,量
	{
		edges[e]=Node(v,cap,head[u]);
		head[u]=e++;
		edges[e]=Node(u,0,head[v]);
		head[v]=e++;
	}

    int SAP ()
    {
        int u,v,i,maxflow=0;   //总最大流
        s=1;
        t=n;
        u=s;
        flow[s]=INF;
        for (i=1;i<=n;i++)
			curedge[i]=head[i];     //当前弧初始化
        BFS ();
        cnt[0]=n;
        while (dis[s]<n)
        {
            for (i=curedge[u];i!=0;i=edges[i].next)        //找允许弧
                if (edges[i].cap && dis[edges[i].v]+1==dis[u])
					break;
            if (i!=0)      //存在允许弧
            {
                curedge[u]=i;         //设置当前弧
                v=edges[i].v;
                if (edges[i].cap<flow[u])
					flow[v]=edges[i].cap;
                else
					flow[v]=flow[u];  //标记当前顶点为止经过的最小弧
                u=v;
                pre[v]=i;  //前置顶点边号
                if (u==t)
                {
                    do
                    {
                        edges[pre[u]].cap-=flow[t];          //正向弧减a[t]
                        edges[pre[u]^1].cap+=flow[t];        //通过异或操作找反向弧
                        u=edges[pre[u]^1].v;
                    }
                    while (u!=s);
                    maxflow+=flow[t];
                    //memset(flow,0,sizeof(flow));
                    flow[s]=INF;
                }
            }
            else   //不存在允许弧
            {
                if (--cnt[dis[u]]==0)
					break;     //间隙优化
                dis[u]=n;
                curedge[u]=head[u];
                for (i=head[u];i!=0;i=edges[i].next)
                    if (edges[i].cap && dis[edges[i].v]+1<dis[u])
                        dis[u]=dis[edges[i].v]+1;       //修改距离标号为 最小的非允许弧加1
                cnt[dis[u]]++;
                if (u!=s)
					u=edges[pre[u]^1].v;
            }
        }
        return maxflow;
    }
};

int m,n;
MNF_SAP ob;

int main()  
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
		ob.init(m*n+2);
		int s=1;    //源点
		int t=m*n+2;   //汇点
		int temp,sum=0;
        for (int i=1;i<=m;i++)
			for (int j=1;j<=n;j++)
			{
				scanf("%d",&temp);
				sum+=temp;
				if ((i+j)%2==0)
				{
					ob.Add (s,(i-1)*n+j+1,temp);
					if (i>1)   //点不在第一行
						ob.Add((i-1)*n+j+1,(i-2)*n+j+1,INF);
					if (j>1)   //点不在第一列
						ob.Add((i-1)*n+j+1,(i-1)*n+j,INF);
					if (i<m)  //点不在最后一行
						ob.Add((i-1)*n+j+1,i*n+j+1,INF);
					if (j<n)  //点不在最后一列
						ob.Add((i-1)*n+j+1,(i-1)*n+j+1+1,INF);
				}
				else
					ob.Add((i-1)*n+j+1,t,temp);
			}
			printf("%d\n",sum-ob.SAP());
	}
	return 0;  
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: