码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3232 圈地游戏——0/1分数规划(或网络流)

时间:2018-09-26 20:11:16      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:str   ring   first   网络流   eps   pre   href   www   space   

题目: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\n",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\n",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\n",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\n",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\n",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\n",x,y,cnt[x][y],dis[x][y]);
//        if(mid>2&&mid<3)printf("fa[%d][%d]=(%d,%d)\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",ans);
    return 0;
}

 

bzoj 3232 圈地游戏——0/1分数规划(或网络流)

标签:str   ring   first   网络流   eps   pre   href   www   space   

原文地址:https://www.cnblogs.com/Narh/p/9709181.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!