天天看點

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\n",ans);
    return 0;
}                

轉載于:https://www.cnblogs.com/lokiii/p/9795805.html