您的位置:首页 > 其它

【NOI2009】bzoj1565 植物大战僵尸

2017-01-23 19:55 477 查看
Description Input Output

仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

最大权闭合子图。注意如果有环,那么环和环的后继是都不能选的,可以拓扑排序找出来。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int s=1005,t=1006,oo=0x3f3f3f3f;
int f1[1010],n1[2000010],t1[2000010],w1[2000010],que[1010],f[1010],
ok[1010],du[1010],out[1010],f2[1010],n2[2000010],t2[2000010],a[1010],
n,m,tot1,tot2,sum;
void a1(int u,int v,int x)
{
tot1++;
n1[tot1*2]=f1[u];
f1[u]=tot1*2;
t1[tot1*2]=v;
w1[tot1*2]=x;
n1[tot1*2+1]=f1[v];
f1[v]=tot1*2+1;
t1[tot1*2+1]=u;
w1[tot1*2+1]=0;
}
void a2(int u,int v)
{
du[v]++;
n2[++tot2]=f2[u];
f2[u]=tot2;
t2[tot2]=v;
}
void init()
{
int i,j,k,x,y;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{
scanf("%d%d",&a[i*m+j],&k);
while (k--)
{
scanf("%d%d",&x,&y);
x++;y++;
a1(x*m+y,i*m+j,oo);
a2(i*m+j,x*m+y);
}
}
for (i=1;i<=n;i++)
for (j=1;j<m;j++)
{
a1(i*m+j,i*m+j+1,oo);
a2(i*m+j+1,i*m+j);
}
}
void top()
{
int i,j,u,v,hd=1,tl=0;
/*for (int i=1;i<=t;i++)
for (int j=f2[i];j;j=n2[j])
printf("%d->%d\n",i,t2[j]);*/
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (du[i*m+j]==0)
que[++tl]=i*m+j;
while (hd<=tl)
{
u=que[hd++];
ok[u]=1;
for (i=f2[u];i;i=n2[i])
if (--du[v=t2[i]]==0)
que[++tl]=v;
}
}
void build()
{
int i,j;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (ok[i*m+j])
{
if (a[i*m+j]>=0)
{
sum+=a[i*m+j];
a1(s,i*m+j,a[i*m+j]);
}
else a1(i*m+j,t,-a[i*m+j]);
}
}
bool bfs()
{
int i,j,u,v,hd,tl;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
f[i*m+j]=0;
f[t]=0;
f[que[1]=s]=hd=tl=1;
while (hd<=tl)
{
u=que[hd++];
for (i=f1[u];i;i=n1[i])
if (w1[i]&&!f[v=t1[i]])
{
que[++tl]=v;
f[v]=f[u]+1;
}
}
return f[t];
}
int dfs(int u,int lim)
{
if (u==t) return lim;
int i,v,x,ret=0;
for (i=f1[u];i&&ret<lim;i=n1[i])
if (w1[i]&&f[v=t1[i]]==f[u]+1)
{
x=dfs(v,min(lim-ret,w1[i]));
w1[i]-=x;
w1[i^1]+=x;
ret+=x;
}
if (!ret) f[u]=0;
return ret;
}
int solve()
{
int ans=0,x;
while (bfs())
while (x=dfs(s,oo))
ans+=x;
return sum-ans;
}
int main()
{
init();
top();
build();
/*for (int i=1;i<=t;i++)
for (int j=f1[i];j;j=n1[j])
if (w1[j])
printf("%d->%d:%d\n",i,t1[j],w1[j]);*/
printf("%d\n",solve());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息