Description
Input
Output
仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。
Sample Input
3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
Sample Output
25
HINT
在样例中, 植物
P1,1
P
1
,
1
可以攻击位置
(0,0)
(
0
,
0
)
,
P2,0
P
2
,
0
可以攻击位置
(2,1)
(
2
,
1
)
。
一个方案为,首先进攻
P1,1,P0,1
P
1
,
1
,
P
0
,
1
,此时可以攻击
P0,0
P
0
,
0
。共得到能源收益为
(−5)+20+10=25
(
−
5
)
+
20
+
10
=
25
。注意, 位置
(2,1)
(
2
,
1
)
被植物
P2,0
P
2
,
0
保护,所以无法攻击第
2
2
行中的任何植物。
大致数据规模
约20%的数据满足;
约40%的数据满足
1≤N,M≤10
1
≤
N
,
M
≤
10
;
约100%的数据满足
1≤N≤20
1
≤
N
≤
20
,
1≤M≤30
1
≤
M
≤
30
,
−10000≤Score≤10000
−
10000
≤
S
c
o
r
e
≤
10000
。
Source
思路
典型的二元组建图,注意有些地方永远都不能攻击到,需要先拓扑排序判断这些点,从网络流中剔除出这些点。
代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
const int maxn=600;
const int maxm=400000;
const int inf=0x3f3f3f3f;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int n,m,s,t;
struct network_flow
{
int pre[maxm+10],now[maxn+10],son[maxm+10],tot,val[maxm+10],d[maxn+10];
inline int clear()
{
memset(now,0,sizeof now);
tot=1;
return 0;
}
inline int ins(int a,int b,int c)
{
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
val[tot]=c;
return 0;
}
inline int add(int a,int b,int c)
{
ins(a,b,c);
ins(b,a,0);
return 0;
}
inline int bfs()
{
std::queue<int> q;
q.push(s);
memset(d,-1,sizeof d);
d[s]=0;
while(!q.empty())
{
int u=q.front(),j=now[u];
q.pop();
while(j)
{
int v=son[j];
if(val[j]&&(d[v]==-1))
{
d[v]=d[u]+1;
if(v==t)
{
return 1;
}
q.push(v);
}
j=pre[j];
}
}
return 0;
}
int dfs(int u,int flow)
{
if(u==t)
{
return flow;
}
int j=now[u],res=flow;
while(j&&res)
{
int v=son[j];
if(val[j]&&(d[v]==d[u]+1))
{
int k=dfs(v,std::min(res,val[j]));
if(!k)
{
d[v]=-1;
}
val[j]-=k;
val[j^1]+=k;
res-=k;
}
j=pre[j];
}
return flow-res;
}
inline int dinic()
{
int ans=0;
while(bfs())
{
ans+=dfs(s,inf);
}
return ans;
}
};
struct graph
{
int pre[maxm+10],now[maxn+10],son[maxm+10],tot,b[maxn+10],ru[maxn+10],stack[maxn+10],head;
inline int clear()
{
memset(now,0,sizeof now);
tot=0;
return 0;
}
inline int ins(int a,int bx)
{
pre[++tot]=now[a];
now[a]=tot;
son[tot]=bx;
ru[bx]++;
return 0;
}
inline int graph_sort()
{
head=0;
memset(b,0,sizeof b);
for(register int i=1; i<=n*m; ++i)
{
if(!ru[i])
{
stack[++head]=i;
b[i]=1;
}
}
while(head)
{
int u=stack[head--],j=now[u];
while(j)
{
int v=son[j];
--ru[v];
if(!ru[v])
{
stack[++head]=v;
b[v]=1;
}
j=pre[j];
}
}
return 0;
}
};
network_flow f;
graph g;
int ans,score[maxn+10],minnum;
int main()
{
n=read();
m=read();
s=0;
t=n*m+1;
minnum=inf;
g.clear();
f.clear();
for(register int i=1; i<=n*m; ++i)
{
score[i]=read();
minnum=std::min(minnum,score[i]);
int k=read();
while(k--)
{
int x=read(),y=read();
g.ins(i,x*m+y+1);
}
}
if(minnum>=0)
{
minnum=0;
}
else
{
minnum=-minnum;
}
for(register int i=0; i<n; ++i)
{
for(register int j=1; j<m; ++j)
{
g.ins(i*m+j+1,i*m+j);
}
}
g.graph_sort();
for(register int i=1; i<=n*m; ++i)
{
if(g.b[i])
{
f.add(i,t,score[i]+minnum);
f.add(s,i,minnum);
int j=g.now[i];
while(j)
{
int v=g.son[j];
if(g.b[v])
{
f.add(i,v,inf);
}
j=g.pre[j];
}
ans+=score[i]+minnum;
}
}
printf("%d\n",ans-f.dinic());
return 0;
}