在样例中, 植物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<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<queue> #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<int> v[N]; queue<int> 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<v[x].size();i++) { int y=v[x][i];ind[y]--; if (!ind[y]) q.push(y); } } F(i,1,n*m) if (!ind[i]) { if (w[i]>=0) add_edge(s,i,w[i]),ans+=w[i]; else add_edge(i,t,-w[i]); for(int j=0;j<v[i].size();j++) { int x=v[i][j]; if (!ind[x]) add_edge(x,i,inf); } } ans-=dinic(); printf("%d\n",ans); }