zoukankan      html  css  js  c++  java
  • bzoj 3232 圈地游戏——0/1分数规划(或网络流)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3232

    当然是0/1分数规划。但加的东西和减的东西不在一起,怎么办?

    考虑把它们合在一起。因为边围成的形状像一个环,所以把格子的贡献也放到边上,然后正常判环。

    放到边上的方法就是:比如竖着的边,可以在每一行上维护该行格子值前缀和,然后指定那个围成的形状是,比如,逆时针的,那么向上的边就加上到它为止的前缀值,向下的边就减去到它为止的前缀值,然后就能判环了!

    这样一定只有一个环。但多个环答案不会更优。

    还可以用网络流。与 s 相连表示选、与 t 相连表示不选的话,每个点到 s 连该点权值的边,到 t 连边权为0的边,相邻点之间连它们夹着的边权值的边,这样如果相邻的点一个选了一个没选,就得割它们之间的那条边,就能表示了。

    自己写了判环的那个。

    注意如果以竖着的边算了围住的部分,就不要再用横着的边同时算了!!

    请把 eps 设成 1e-7 而不是 1e-5 。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define db double
    using namespace std;
    const int N=55,M=N*N;
    const db eps=1e-7;
    int n,m,fl[N][N]/*,fu[N][N]*/,eh[N][N],el[N][N],cnt[N][N],tot;
    db l,r,mid,ans,dis[N][N],w[N][N][5];
    bool vis[N][N];
    queue<pair<int,int> > q;
    bool spfa()
    {
    //    printf("mid=%.3lf
    ",mid);
        while(q.size())q.pop();
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++)
            {
                q.push(make_pair(i,j));
                vis[i][j]=1; dis[i][j]=0; cnt[i][j]=0;
                if(i)
                {
                    w[i][j][0]=fl[i][j]-mid*el[i][j];
    //                if(mid<3&&mid>2&&el[i][j]==1)
    //                printf("w[%d][%d][0]=%.3lf
    ",i,j,w[i][j][0]);
                }
                if(j)
                {
                    w[i][j][1]=/*-fu[i][j]*/-mid*eh[i][j];
    //                if(mid<3&&mid>2&&eh[i][j]==1)
    //                printf("w[%d][%d][1]=%.3lf
    ",i,j,w[i][j][1]);
                }
                if(i<n)
                {
                    w[i][j][3]=-fl[i+1][j]-mid*el[i+1][j];
    //                if(mid<3&&mid>2&&el[i+1][j]==1)
    //                printf("w[%d][%d][3]=%.3lf
    ",i,j,w[i][j][3]);
                }
                if(j<m)
                {
                    w[i][j][2]=/*fu[i][j+1]*/-mid*eh[i][j+1];
    //                if(mid<3&&mid>2&&eh[i][j+1]==1)
    //                printf("w[%d][%d][2]=%.3lf
    ",i,j,w[i][j][2]);
                }
            }
        while(q.size())
        {
            int x=q.front().first,y=q.front().second;
            q.pop();
            vis[x][y]=0;
    //        if(mid>2&&mid<3)printf("x=%d y=%d cnt=%d dis=%.3lf
    ",x,y,cnt[x][y],dis[x][y]);
    //        if(mid>2&&mid<3)printf("fa[%d][%d]=(%d,%d)
    ",x,y,fa[x][y][0],fa[x][y][1]);
            if(x&&dis[x-1][y]<dis[x][y]+w[x][y][0])
            {
                dis[x-1][y]=dis[x][y]+w[x][y][0];
    //            printf("  w[%d][%d][0]=%.3lf
    ",x,y,w[x][y][0]);
    //            fa[x-1][y][0]=x; fa[x-1][y][1]=y;
                cnt[x-1][y]=cnt[x][y]+1;
                if(cnt[x-1][y]==tot)
                {
    //                if(mid>2&&mid<3)
    //                    printf("x-1=%d y=%d dis=%.3lf
    ",x-1,y,dis[x-1][y]);
                    return 1;
                }
                if(!vis[x-1][y])
                    vis[x-1][y]=1,q.push(make_pair(x-1,y));
            }
            if(y&&dis[x][y-1]<dis[x][y]+w[x][y][1])
            {
                dis[x][y-1]=dis[x][y]+w[x][y][1];
    //            printf("  w[%d][%d][1]=%.3lf
    ",x,y,w[x][y][1]);
    //            fa[x][y-1][0]=x; fa[x][y-1][1]=y;
                cnt[x][y-1]=cnt[x][y]+1;
                if(cnt[x][y-1]==tot)
                {
    //                if(mid>2&&mid<3)
    //                    printf("x=%d y-1=%d dis=%.3lf
    ",x,y-1,dis[x][y-1]);
                    return 1;
                }
                if(!vis[x][y-1])
                    vis[x][y-1]=1,q.push(make_pair(x,y-1));
            }
            if(x<n&&dis[x+1][y]<dis[x][y]+w[x][y][3])
            {
                dis[x+1][y]=dis[x][y]+w[x][y][3];
    //            printf("  w[%d][%d][3]=%.3lf
    ",x,y,w[x][y][3]);
    //            fa[x+1][y][0]=x; fa[x+1][y][1]=y;
                cnt[x+1][y]=cnt[x][y]+1;
                if(cnt[x+1][y]==tot)
                {
    //                if(mid>2&&mid<3)
    //                    printf("x+1=%d y=%d dis=%.3lf
    ",x+1,y,dis[x+1][y]);
                    return 1;
                }
                if(!vis[x+1][y])
                    vis[x+1][y]=1,q.push(make_pair(x+1,y));
            }
            if(y<m&&dis[x][y+1]<dis[x][y]+w[x][y][2])
            {
                dis[x][y+1]=dis[x][y]+w[x][y][2];
    //            printf("  w[%d][%d][2]=%.3lf
    ",x,y,w[x][y][4]);
    //            fa[x][y+1][0]=x; fa[x][y+1][1]=y;
                cnt[x][y+1]=cnt[x][y]+1;
                if(cnt[x][y+1]==tot)
                {
    //                if(mid>2&&mid<3)
    //                    printf("x=%d y+1=%d dis=%.3lf
    ",x,y+1,dis[x][y+1]);
                    return 1;
                }
                if(!vis[x][y+1])
                    vis[x][y+1]=1,q.push(make_pair(x,y+1));
            }
        }
        return 0;
    }
    int main()
    {
        scanf("%d%d",&n,&m); tot=(n+1)*(m+1);//+1!!!
        for(int i=1;i<=n;i++)
            for(int j=1,d;j<=m;j++)
            {
                scanf("%d",&d); r+=d;
                fl[i][j]=fl[i][j-1]+d;
    //            fu[i][j]=fu[i-1][j]+d;
            }
        for(int i=0;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&eh[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)
                scanf("%d",&el[i][j]);
        while(r-l>eps)
        {
            mid=(l+r)/2;
            if(spfa()) ans=mid,l=mid+eps;
            else r=mid-eps;
        }
        printf("%.3lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    MongoDB 之 手把手教你增删改查 MongoDB
    MongoDB 之 你得知道MongoDB是个什么鬼 MongoDB
    全栈12期的崛起之捡点儿有用的说说
    Python 常用模块
    Python3中的内置函数
    Python程序员之面试必回习题
    Django之初始庐山真面目
    Django之ORM操作
    MySQL-索引
    MySQL-函数
  • 原文地址:https://www.cnblogs.com/Narh/p/9709181.html
Copyright © 2011-2022 走看看