正题
P2805
题目大意
在一个n×mn\times mn×m的平面上有若干植物,每个植物有其攻击集合,吃掉一个植物要先吃掉该植物右边的所有植物,且该植物不能在任何一个植物的攻击集合内,吃掉后有贡献ai,ja_{i,j}ai,j,问你最大贡献
解题思路
先按植物先后吃的顺序连边,然后跑拓扑序判断哪些植物能吃
然后直接对能吃的植物跑最大权闭合子图
code
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 610
using namespace std;
int n,m,x,y,g,s,t,nm,ans,tot,tott,v[N],h[N],hd[N],dep[N],deg[N];
queue<int>d;
struct rec
{int to,nx,edge;
}e[N*N<<1];
struct recc
{int to,nx;
}a[N*N];
const int inf=1e8;
int get(int x,int y)
{return x*m+y;
}
void add(int x,int y)
{a[++tott].to=y;a[tott].nx=hd[x];hd[x]=tott;deg[y]++;return;
}
void addl(int x,int y,int z)
{e[++tot].to=y;e[tot].edge=z;e[tot].nx=h[x];h[x]=tot;e[++tot].to=x;e[tot].edge=0;e[tot].nx=h[y];h[y]=tot;return;
}
void prebfs()
{for(int i=0;i<=nm;++i)if(!deg[i]){d.push(i);if(v[i]>0){ans+=v[i];addl(s,i,v[i]);}else if(v[i]<0)addl(i,t,-v[i]);}while(!d.empty()){int x=d.front();d.pop();for(int i=hd[x];i;i=a[i].nx){int y=a[i].to;deg[y]--;if(!deg[y]){d.push(y);if(v[y]>0){ans+=v[y];addl(s,y,v[y]);}else if(v[y]<0)addl(y,t,-v[y]);}}}return;
}
bool bfs()
{memset(dep,0,sizeof(dep));dep[s]=1;while(!d.empty())d.pop();d.push(s);while(!d.empty()){int x=d.front();d.pop();for(int i=h[x];i;i=e[i].nx){int y=e[i].to;if(dep[y]||!e[i].edge)continue;dep[y]=dep[x]+1;if(y==t)return true;d.push(y);}}return false;
}
int dfs(int x,int flow)
{if(x==t)return flow;int rest=0,k;for(int i=h[x];i;i=e[i].nx){int y=e[i].to;if(dep[y]!=dep[x]+1||!e[i].edge)continue;k=dfs(y,min(e[i].edge,flow-rest));if(!k)dep[y]=0;rest+=k;e[i].edge-=k;e[i^1].edge+=k;if(flow==rest)return rest;}return rest;
}
int main()
{scanf("%d%d",&n,&m);nm=get(n-1,m-1);s=nm+1;t=nm+2;tot=1;for(int i=0;i<n;++i)for(int j=0;j<m;++j){scanf("%d",&v[get(i,j)]);scanf("%d",&g);for(int k=1;k<=g;++k){scanf("%d%d",&x,&y);add(get(i,j),get(x,y));addl(get(x,y),get(i,j),inf);}if(j){add(get(i,j),get(i,j-1));addl(get(i,j-1),get(i,j),inf);}}prebfs();while(bfs())ans-=dfs(s,inf);printf("%d",ans);return 0;
}