數組開小導緻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