• 「网络流24题」 9. 方格取数问题


    「网络流24题」 9. 方格取数问题

    <题目链接>


    二分图的最大点权独立集

    建立二分图,使得每个点与其相邻的点在不同的部。

    源向X部引有向边,Y部向汇引有向边,边权为点权。

    X部每个点到其相邻的点引有向边,边权INF,这个边的两个断电不能同时被选。

    那么S-X-Y-T的任意一条增广路都表示选了两个相邻的点。

    于是问题转化为求网络最小割。

    最终的答案为所有点的点权和(先都选上)减去网络最小割(不能选的最小点权集)。

    #include <algorithm>
    #include <climits>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int MAXN=10010,MAXM=59610;
    int m,n,S,T,cnt,ans,head[MAXN],cur[MAXN],dis[MAXN];
    struct edge
    {
    	int nxt,to,w;
    }e[MAXM];
    void AddEdge(int x,int y,int w)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	e[cnt].w=w;
    	head[x]=cnt;
    }
    void AddEdges(int x,int y,int w)
    {
    	AddEdge(x,y,w);
    	AddEdge(y,x,0);
    }
    int num(int i,int j)
    {
    	return (i-1)*n+j;
    }
    void Init(int i,int j)
    {
    	int w,t=num(i,j);
    	scanf("%d",&w);
    	ans+=w;
    	if(i+j&1)
    		AddEdges(t,T,w);
    	else
    	{
    		AddEdges(S,t,w);
    		if(i>1)
    			AddEdges(t,t-n,INT_MAX);
    		if(i<m)
    			AddEdges(t,t+n,INT_MAX);
    		if(j>1)
    			AddEdges(t,t-1,INT_MAX);
    		if(j<n)
    			AddEdges(t,t+1,INT_MAX);
    	}
    }
    bool BFS(void)
    {
    	queue<int> q;
    	memset(dis,0,sizeof dis);
    	q.push(S);
    	dis[S]=1;
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		for(int i=head[x],t;i;i=e[i].nxt)
    			if(e[i].w && !dis[t=e[i].to])
    			{
    				q.push(t);
    				dis[t]=dis[x]+1;
    			}
    	}
    	return dis[T];
    }
    int DFS(int x,int k)
    {
    	if(x==T || !k)
    		return k;
    	int tmp=0;
    	for(int i=cur[x],t,flow;i;i=e[i].nxt)
    		if(e[i].w && dis[t=e[i].to]==dis[x]+1 && (flow=DFS(t,min(k,e[i].w))))
    		{
    			cur[x]=i;
    			e[i].w-=flow;
    			e[((i-1)^1)+1].w+=flow;
    			k-=flow;
    			tmp+=flow;
    		}
    	if(!tmp)
    		dis[x]=0;
    	return tmp;
    }
    void Dinic(void)
    {
    	int flow;
    	while(BFS())
    		while(memcpy(cur,head,sizeof cur),flow=DFS(S,INT_MAX))
    			ans-=flow;
    }
    int main(int argc,char *argv[])
    {
    	scanf("%d %d",&m,&n);
    	T=m*n+1;
    	for(int i=1;i<=m;++i)
    		for(int j=1;j<=n;++j)
    			Init(i,j);
    	Dinic();
    	printf("%d",ans);
    	return 0;
    }
    

    谢谢阅读

  • 相关阅读:
    如何在Windows下安装sass和compass
    HTTP 请求头中的 X-Forwarded-For
    HTTP 代理原理及实现
    node.js使用经验记录
    完美方案——iOS的WebView自适应内容高度
    购物车商品加减效果
    C++17新特性
    栈实现迷宫求解(c++版)
    二叉树遍历及实现
    经典乱码“烫烫烫”和“屯屯屯”
  • 原文地址:https://www.cnblogs.com/Capella/p/8185107.html
Copyright © 2020-2023  润新知