• [bzoj3232]圈地游戏【0/1分数规划】【网络流】


    【题目描述】

    Description

    DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用。
    DZY喜欢在地里散步。他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或触碰(出发点除外)。记这条封闭路线内部的格子总价值为V,路线上的费用总和为C,DZY想知道V/C的最大值是多少。

    Input

    第一行为两个正整数n,m。
    接下来n行,每行m个非负整数,表示对应格子的价值。
    接下来n+1行,每行m个正整数,表示所有横向的格线上的费用。
    接下来n行,每行m+1个正整数,表示所有纵向的格线上的费用。
    (所有数据均按从左到右,从上到下的顺序输入,参见样例和配图)

    Output

     
    输出一行仅含一个数,表示最大的V/C,保留3位小数。

    Sample Input

    3 4
    1 3 3 3
    1 3 1 1
    3 3 1 0
    100 1 1 1
    97 96 1 1
    1 93 92 92
    1 1 90 90
    98 1 99 99 1
    95 1 1 1 94
    1 91 1 1 89

    Sample Output

    1.286

    HINT

    Source

    【题解】

     看到求比值就知道这题一定要0/1分数规划,关键是怎么判断答案是否可行。

     题目可以转换为最大全闭合子图的模型,

    原点S 往每个点连边,流量为这个点的权值

    相邻的点互相连边,流量为这两个点夹着的割线的费用。

    在最外圈的点往T连边,流量为这个点所靠边界的费用。

    当前答案=权值和-最大流

    直观感受,割掉与S的边相当于不选这个点,割掉相邻个点的边相当于一个选一个不选,割掉连向T的边说明选这个边界上的点。

    /* --------------
        user Vanisher
        problem bzoj-3232
    ----------------*/
    # include <bits/stdc++.h>
    # define 	ll 		long long
    # define 	inf 	1e9
    # define 	eps 	1e-5
    # define 	N 		110
    # define 	M 		1000100
    using namespace std;
    int read(){
    	int tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    struct node{
    	int data,next,re;
    	double l;
    }e[M];
    int head[N*N],place,S,T,dis[N*N],q[N*N],now[N*N],n,m,p[N][N],w[N][N],sum,cx[N][N],cy[N][N];
    void build(int u, int v, double l){
    	e[++place].data=v; e[place].next=head[u]; head[u]=place; e[place].l=l; e[place].re=place+1;
    	e[++place].data=u; e[place].next=head[v]; head[v]=place; e[place].l=0; e[place].re=place-1;
    }
    void bfs(){
    	for (int i=1; i<=T; i++) dis[i]=inf;
    	int pl=1, pr=1; q[1]=S;
    	while (pl<=pr){
    		int x=q[pl++];
    		for (int ed=head[x]; ed!=0; ed=e[ed].next)
    			if (dis[e[ed].data]==inf&&e[ed].l>=eps)
    				dis[e[ed].data]=dis[x]+1, q[++pr]=e[ed].data;
    	}
    }
    double dfs(int x, double flow){
    	if (x==T) return flow;
    	double sum=0;
    	for (int ed=now[x]; ed!=0; ed=e[ed].next)
    		if (e[ed].l>=eps&&dis[e[ed].data]==dis[x]+1){
    			double tmp=dfs(e[ed].data,min(flow,e[ed].l));
    			sum=sum+tmp; flow=flow-tmp;
    			e[ed].l-=tmp; e[e[ed].re].l+=tmp;
    			if (flow<eps){
    				now[x]=ed;
    				return sum;
    			}
    		}
    	now[x]=0;
    	return sum;
    }
    double dinic(){
    	double sum=0;
    	for (bfs(); dis[T]!=inf; bfs()){
    		for (int i=S; i<=T; i++) now[i]=head[i];
    		sum=sum+dfs(S,inf);
    	}
    	return sum;
    }
    double check(double d){
    	place=0; memset(head,0,sizeof(head));
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<=m; j++)
    			build(S,p[i][j],w[i][j]);
    	for (int i=1; i<=n-1; i++)
    		for (int j=1; j<=m; j++)
    			build(p[i][j],p[i+1][j],cx[i+1][j]*d);
    	for (int i=2; i<=n; i++)
    		for (int j=1; j<=m; j++)
    			build(p[i][j],p[i-1][j],cx[i][j]*d);
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<=m-1; j++)
    			build(p[i][j],p[i][j+1],cy[i][j+1]*d);
    	for (int i=1; i<=n; i++)
    		for (int j=2; j<=m; j++)
    			build(p[i][j],p[i][j-1],cy[i][j]*d);
    	for (int i=1; i<=n; i++){
    		build(p[i][1],T,cy[i][1]*d);
    		build(p[i][m],T,cy[i][m+1]*d);
    	}
    	for (int i=1; i<=m; i++){
    		build(p[1][i],T,cx[1][i]*d);
    		build(p[n][i],T,cx[n+1][i]*d);
    	}
    	return sum-dinic();
    }
    int main(){
    	n=read(), m=read(); S=0;
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<=m; j++){
    			w[i][j]=read(), sum=sum+w[i][j];
    			p[i][j]=++place;
    		}
    	T=++place;
    	for (int i=1; i<=n+1; i++)
    		for (int j=1; j<=m; j++)
    			cx[i][j]=read();
    	for (int i=1; i<=n; i++)
    		for (int j=1; j<=m+1; j++)
    			cy[i][j]=read();
    	double pl=0, pr=10000.00, ans=0;
    	while (pl<=pr){
    		double mid=(pl+pr)/2;
    		if (check(mid)>eps)
    			ans=mid, pl=mid+eps;
    			else pr=mid-eps;
    	}
    	printf("%.3lf",ans);
    	return 0;
    }
    


  • 相关阅读:
    python 数据结构 图解递归 海龟画图分形树
    python 数据结构 理解迭代与递归 递归的实例 栈帧 函数调用
    python 数据结构 双端队列的两种实现方式 list 和 DoublelinkedList 回文词验证
    python 数据结构 实现队列的几种方法
    python 数据结构 实现链队的两种方法
    python 数据结构 查找数组最值
    python 数据结构 队列的实例 回文词与双端队列
    双向链表练习题
    均分纸牌问题
    L1-8 估值一亿的AI核心代码
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136030.html
Copyright © 2020-2023  润新知