bzoj 3232: 圈地游戏分数规划+最小割

Posted lokiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3232: 圈地游戏分数规划+最小割相关的知识,希望对你有一定的参考价值。

数组开小导致TTTTTLE……
是分数规划,设sm为所有格子价值和,二分出mid之后,用最小割来判断,也就是判断sm-dinic()>=0
这个最小割比较像最大权闭合子图,建图是s像所有点连流量为格子价值的边(相当于最大权闭合子图中的正权点),然后考虑边缘,两个相邻的格子,如果一个选一个不选那么中间这条边就有负的贡献,所以两个相邻的格子之间连两条边权为mid*边权的边,注意是两条,要互相连一下,然后所有边界上的点像t连边权为mid*边界边权的边,相当于假装外面还有一层点全标为t,然后跑最小割判断即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=105;
const double eps=1e-6,inf=1e9;
int n,m,h[N*N],cnt,s,t,id[N][N],tot,le[N*N];
double a[N][N],b[N][N],c[N][N],sm;
struct qwe
{
    int ne,to;
    double va;
}e[N*N*N];
void add(int u,int v,double w)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    e[cnt].va=w;
    h[u]=cnt;
}
void ins(int u,int v,double w)
{
    add(u,v,w);
    add(v,u,0);
}
bool bfs()
{
    queue<int>q;
    memset(le,0,sizeof(le));
    le[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].va>eps&&!le[e[i].to])
            {
                le[e[i].to]=le[u]+1;
                q.push(e[i].to);
            }
    }
    return le[t];
}
double dfs(int u,double f)
{
    if(u==t||!f)
        return f;
    double us=0;
    for(int i=h[u];i&&us<f;i=e[i].ne)
        if(e[i].va>eps&&le[e[i].to]==le[u]+1)
        {
            double t=dfs(e[i].to,min(e[i].va,f-us));
            e[i].va-=t;
            e[i^1].va+=t;
            us+=t;
        }
    if(us<eps)
        le[u]=0;
    return us;
}
int dinic()
{
    double re=0;
    while(bfs())
        re+=dfs(s,inf);
    return re;
}
bool ok(double w)
{
    memset(h,0,sizeof(h));
    cnt=1,s=0,t=n*m+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ins(s,id[i][j],a[i][j]);
    for(int j=1;j<=m;j++)
        ins(id[1][j],t,w*b[0][j]),ins(id[n][j],t,w*b[n][j]);
    for(int i=1;i<=n;i++)
        ins(id[i][1],t,w*c[i][0]),ins(id[i][m],t,w*c[i][m]);
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
            add(id[i][j],id[i+1][j],w*b[i][j]),add(id[i+1][j],id[i][j],w*b[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<m;j++)
            add(id[i][j],id[i][j+1],w*c[i][j]),add(id[i][j+1],id[i][j],w*c[i][j]);
    return sm-dinic()>eps;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%lf",&a[i][j]),id[i][j]=++tot,sm+=a[i][j];
    for(int i=0;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%lf",&b[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            scanf("%lf",&c[i][j]);
    double l=0,r=n*m*100,ans=0;
    while(r-l>1e-5)
    {
        double mid=(l+r)/2;
        if(ok(mid))
            l=mid,ans=mid;
        else
            r=mid;
    }
    printf("%.3f
",ans);
    return 0;
}


以上是关于bzoj 3232: 圈地游戏分数规划+最小割的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3232 圈地游戏 —— 01分数规划+最小割建图(最大权闭合子图)

BZOJ 3232: 圈地游戏 分数规划+判负环

BZOJ 3232圈地游戏 二分+SPFA判环/最小割经典模型

bzoj3232 圈地游戏

BZOJ2132圈地计划(最小割)

BZOJ2132圈地计划 最小割