在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。
一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。
【大致数据规模】
约20%的数据满足1 ≤ N, M ≤ 5;
约40%的数据满足1 ≤ N, M ≤ 10;
约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。
网络流+最大权闭合子图+拓扑排序
这道题有一个隐藏条件:每个植物除了保护给出的位置外,还保护它左面的节点。
然后把所有植物的保护关系建出图,有一些植物之间是环状结构的,这显然不能被吃,所以我们用拓扑排序去掉图中的环。
题目转化为:有一些点,点有点权,吃掉某一个点必须先吃掉某些点,求最多能吃掉的权值。
这符合最大权闭合子图的定义,用最小割求最大权闭合子图即可。
最大权闭合子图求法详见bzoj1497。
#include
#include
#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define p(x,y) ((x-1)*m+y)
#define ll long long
#define N 1000
#define M 800005
#define inf 1000000000
using namespace std;
int n,m,s,t,cnt=1,ans;
int w[N],ind[N],head[N],cur[N],dis[N];
vector v[N];
queue q;
struct edge{int next,to,v;}e[M];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x,int y,int v)
{
e[++cnt]=(edge){head[x],y,v};head[x]=cnt;
e[++cnt]=(edge){head[y],x,0};head[y]=cnt;
}
bool bfs()
{
while (!q.empty()) q.pop();
memset(dis,-1,sizeof(dis));
dis[s]=0;q.push(s);
while (!q.empty())
{
int x=q.front();q.pop();
if (x==t) return true;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if (e[i].v&&dis[y]==-1) dis[y]=dis[x]+1,q.push(y);
}
}
return false;
}
int dfs(int x,int f)
{
if (x==t) return f;
int sum=0,tmp;
for(int &i=cur[x];i;i=e[i].next)
{
int y=e[i].to;
if (e[i].v&&dis[y]==dis[x]+1)
{
tmp=dfs(y,min(e[i].v,f-sum));
e[i].v-=tmp;e[i^1].v+=tmp;sum+=tmp;
if (sum==f) return sum;
}
}
if (!sum) dis[x]=-1;
return sum;
}
int dinic()
{
int ret=0;
while (bfs())
{
F(i,1,t) cur[i]=head[i];
ret+=dfs(s,inf);
}
return ret;
}
int main()
{
n=read();m=read();s=n*m+1;t=s+1;
F(i,1,n) F(j,1,m)
{
w[p(i,j)]=read();int num=read();
F(k,1,num)
{
int x=read()+1,y=read()+1;
v[p(i,j)].push_back(p(x,y));
ind[p(x,y)]++;
}
}
F(i,1,n) F(j,1,m-1)
{
v[p(i,j+1)].push_back(p(i,j));
ind[p(i,j)]++;
}
F(i,1,n*m) if (!ind[i]) q.push(i);
while (!q.empty())
{
int x=q.front();q.pop();
for(int i=0;i=0) add_edge(s,i,w[i]),ans+=w[i];
else add_edge(i,t,-w[i]);
for(int j=0;j