讲网络流的时候没有听懂最大权闭合子图,然后讲题的时候学长问我们这是什么模型。
我就瞎口胡了最大权闭合子图,然后就中了。
总之,依题可知,要吃一个植物,必须吃它右侧的植物,并且吃掉保护它的植物(全都是玉米加农炮嗷)。所以在两个点之间连一条有向边,连完之后发现要获取一个点的分数必须获取所有它连接的点的分数。
所以就是最大权闭合子图辣。不过由于一个植物可能会保护它自己,或者保护(保护它的植物),所以判环,环与环到达的点统统不拿来建图。建个反图跑拓扑排序就好了。
代码:
#include <bits/stdc++.h>
#define maxn 720005
#define inf 0x3f3f3f
using namespace std;
long long n,m,tot=1,ans=0;
queue <int > q;
int head[maxn],nex[maxn],to[maxn],edge[maxn],cur[maxn];
int mapp[300][300],vis[maxn],lev[maxn];
int attack[605][605],start,endn,cango[maxn];
int in[maxn];
void add(int x,int y,int z){
to[++tot]=y;edge[tot]=z;nex[tot]=head[x];head[x]=tot;
}
int turn(int x,int y){
if (x==0) return 0;
return (x-1)*m+y;
}
int turn1(int x,int y){
return x*m+y+1;
}//这两个turn是转二维坐标为一维用的,看自己喜欢怎么做来咯
void t_sort(){//拓扑排序
for (int i=2;i<=tot;i++){
in[to[i]]++;
}
for (int i=1;i<=n*m;i++) {
if (!in[i]) {
q.push(i);
cango[i]=1;
}
}
while (!q.empty()){
int x=q.front();
q.pop();
cango[x]=1;
for (int i=head[x];i;i=nex[i]){
in[to[i]]--;
if (!in[to[i]]) q.push(to[i]);
}
}
}
void build(){//建图
tot=1;
memset(head,0,sizeof(head));
memset(nex,0,sizeof(nex));
memset(to,0,sizeof(to));
memset(edge,0,sizeof(edge));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
int x=turn(i,j);
if (!cango[x]) continue;
if (j<m) {
add(x,x+1,inf);
add(x+1,x,0);
}
for (int l=1;l<=attack[x][0];l++){
int y=attack[x][l];
if (!cango[y]) continue;
add(y,x,inf);add(x,y,0);
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
int x=turn(i,j);
if (!cango[x]) continue;
if (mapp[i][j]>0)
add(start,x,mapp[i][j]),add(x,start,0),ans+=mapp[i][j];
if (mapp[i][j]<0)
add(x,endn,-mapp[i][j]),add(endn,x,0);
}
}
void f_build(){//建反图,反图只用建原图中的边就好了
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
int x=turn(i,j);
if (j<m) {
add(x+1,x,inf);
}
for (int l=1;l<=attack[x][0];l++){
int y=attack[x][l];
add(x,y,inf);
}
}
}
int bfs(){//bfs定层数,找有无增广路
memset(vis,0,sizeof(vis));
memset(lev,0,sizeof(lev));
q.push(start);vis[start]=1;
while (!q.empty()) {
int x=q.front();
cur[x]=head[x];
q.pop();
for (int i=head[x];i;i=nex[i]) {
int y=to[i];
if (edge[i]>0 && !vis[y]) {
q.push(y);vis[y]=1;lev[y]=lev[x]+1;
}
}
}
if (!lev[endn]) return 0;
else return 1;
}
int dfs(int x,int rest){//dfs找增广路(dinic)
if (x==endn) return rest;
int sum=0;
for (int i=cur[x];i;i=nex[i]){
int y=to[i];
cur[x]=i;
if (edge[i]>0 && lev[y]==lev[x]+1){
int d=dfs(y,min(edge[i],rest-sum));
sum+=d;edge[i]-=d;edge[i^1]+=d;
}
if (sum==rest) break;
}
if (!sum) lev[x]=0;
return sum;
}
void dinic(){
while (bfs()){
ans-=dfs(start,inf);
}
}
int main(){
scanf("%lld%lld",&n,&m);
start=n*m+1;endn=n*m+2;
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++){
int p,w;
scanf("%d%d",&p,&w);
mapp[i][j]=p;
int x=turn(i,j);
attack[x][0]=w;
for (int l=1;l<=w;l++) {
int z,z1;
scanf("%d%d",&z,&z1);
attack[x][l]=turn1(z,z1);
}
}
}
f_build();
t_sort();
build();
dinic();
printf("%lld\n",ans);
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4404541/blog/4493048