• BZOJ 3698 XWW的难题:有上下界的最大流


    传送门

    题意

    给你一个 $ n*n $ 的正实数矩阵 $ A $ ,满足XWW性。

    称一个 $ n*n $ 的矩阵满足XWW性当且仅当:

    • $ A[n][n] = 0 $
    • 矩阵中每行的最后一个元素等于该行前 $ n-1 $ 个数的和(除最后一行)
    • 矩阵中每列的最后一个元素等于该列前 $ n-1 $ 个数的和(除最后一列)

    现在你要给 $ A $ 中的数进行取整操作(可以是上取整或者下取整),使得最后的 $ A $ 矩阵仍然满足XWW性。

    问你 $ A $ 中元素之和最大为多少。如果无解,输出"No"。

    题解

    考虑将每一行和每一列看做一个点。

    首先从源点向每一行 $ R(i) $ 连一条上下界分别为 $ (lfloor A[i][n] floor, lceil A[i][n] ceil) $ 的边,从每一列 $ C(i) $ 向汇点连一条上下界分别为 $ (lfloor A[n][i] floor, lceil A[n][i] ceil) $ 的边。

    然后对于每一个 $ A[i][j] $ 来说,连一条从 $ R(i) $ 到 $ C(i) $ 的上下界为 $ (lfloor A[i][j] floor, lceil A[i][j] ceil) $ 边。

    这样就保证了最大流一定满足了后两个条件。

    然后跑有上下界的有源汇最大流就好。

    AC Code

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <vector>
    #include <queue>
    #define MAX_N 205
    #define INF 1000000000
    #define r(x) (x)
    #define c(x) (n-1+(x))
    
    using namespace std;
    
    struct Edge
    {
    	int dst,cap,rev;
    	Edge(int _dst,int _cap,int _rev) { dst=_dst,cap=_cap,rev=_rev; }
    	Edge(){}
    };
    
    int n,s,t,S,T,tot,dif=0;
    int a[MAX_N];
    int it[MAX_N];
    int lv[MAX_N];
    double w[MAX_N][MAX_N];
    vector<Edge> edge[MAX_N];
    queue<int> q;
    
    void read()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			scanf("%lf",&w[i][j]);
    		}
    	}
    }
    
    inline void add(int s,int t,int c)
    {
    	edge[s].push_back(Edge(t,c,edge[t].size()));
    	edge[t].push_back(Edge(s,0,edge[s].size()-1));
    }
    
    void build()
    {
    	s=(n<<1)-1,t=s+1,S=t+1,T=S+1,tot=T;
    	for(int i=1;i<n;i++)
    	{
    		add(s,r(i),ceil(w[i][n])-floor(w[i][n]));
    		add(c(i),t,ceil(w[n][i])-floor(w[n][i]));
    		a[s]-=floor(w[i][n]),a[r(i)]+=floor(w[i][n]);
    		a[c(i)]-=floor(w[n][i]),a[t]+=floor(w[n][i]);
    	}
    	for(int i=1;i<n;i++)
    	{
    		for(int j=1;j<n;j++)
    		{
    			add(r(i),c(j),ceil(w[i][j])-floor(w[i][j]));
    			a[r(i)]-=floor(w[i][j]),a[c(j)]+=floor(w[i][j]);
    		}
    	}
    	add(t,s,INF);
    	for(int i=1;i<=(n<<1);i++)
    	{
    		if(a[i]>0) dif+=a[i],add(S,i,a[i]);
    		else if(a[i]<0) add(i,T,-a[i]);
    	}
    }
    
    void bfs(int s)
    {
    	memset(lv+1,0,sizeof(int)*tot);
    	q.push(s),lv[s]=1;
    	while(!q.empty())
    	{
    		int x=q.front(); q.pop();
    		for(int i=0;i<edge[x].size();i++)
    		{
    			Edge temp=edge[x][i];
    			if(temp.cap>0 && !lv[temp.dst])
    			{
    				lv[temp.dst]=lv[x]+1;
    				q.push(temp.dst);
    			}
    		}
    	}
    }
    
    int dfs(int x,int t,int f)
    {
    	if(x==t) return f;
    	for(int &i=it[x];i<edge[x].size();i++)
    	{
    		Edge &temp=edge[x][i];
    		if(temp.cap>0 && lv[x]<lv[temp.dst])
    		{
    			int d=dfs(temp.dst,t,min(f,temp.cap));
    			if(d>0)
    			{
    				temp.cap-=d;
    				edge[temp.dst][temp.rev].cap+=d;
    				return d;
    			}
    		}
    	}
    	return 0;
    }
    
    int max_flow(int s,int t)
    {
    	int ans=0,f;
    	while(true)
    	{
    		bfs(s);
    		if(!lv[t]) return ans;
    		memset(it+1,0,sizeof(int)*tot);
    		while((f=dfs(s,t,INF))>0) ans+=f;
    	}
    }
    
    void work()
    {
    	build();
    	int now=max_flow(S,T);
    	if(now!=dif)
    	{
    		printf("No
    ");
    		return;
    	}
    	printf("%d
    ",max_flow(s,t)*3);
    }
    
    int main()
    {
    	read();
    	work();
    }
    
  • 相关阅读:
    SSH Config 那些你所知道和不知道的事 (转)
    解决npm ERR! Unexpected end of JSON input while parsing near的方法
    ES查询-term VS match (转)
    ES查询-match VS match_phrase
    安装使用aria2下载百度网盘内容(转)
    基于CSS3鼠标滑过放大突出效果
    基于jQuery的新浪游戏首页幻灯片
    基于animation.css实现动画旋转特效
    基于jQuery左右滑动切换特效
    基于html5顶部导航3D翻转展开特效
  • 原文地址:https://www.cnblogs.com/Leohh/p/9175419.html
Copyright © 2020-2023  润新知