zoukankan      html  css  js  c++  java
  • 【洛谷2805】[NOI2009] 植物大战僵尸(最大权闭合子图)

    点此看题面

    • 一张(n imes m)的网格图,每个位置上有一个植物。
    • 每个植物有一个价值(可能为负)和一个攻击位置集合,吃一个植物要先吃掉它右边的所有植物以及所有能攻击到这个位置的植物。
    • 求能获得的最大价值。
    • (nle20,mle30)

    最大权闭合子图

    经典问题,完全就是个板子。

    如果吃植物(x)需要先吃植物(y),就从(x)(y)连一条容量为(INF)的边。

    然后令答案的初值为所有正权值之和,从超级源向所有正权点(x)连一条容量为(a_x)的边表示不选的代价,从所有负权点向超级汇连一条容量为(-a_x)的边表示选的代价。

    最后跑一遍最小割=最大流即可。

    拓扑去环

    但实际上还有一个坑点,这道题中可能连出环来!(实际上样例中就有这种情况)

    因此我们要先跑一遍拓扑,则拓扑跑不到的点就是无论如何都无法吃到的点,直接删去。

    注意,由于我们是从被限制的点向限制的点连边的,要在反图上拓扑。(直接拓扑能惊喜地收获80分

    代码:(O(Dinic))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 20
    #define M 30
    #define INF (int)1e9
    #define P(x,y) (((x)-1)*m+(y))
    using namespace std;
    int n,m,a[N*M+5];
    namespace D
    {
    	#define s (n*m+1)
    	#define t (n*m+2)
    	#define adde(x,y,f) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f)
    	const int PS=N*M+2,ES=N*M+N*M*N*M;
    	int ee=1,lnk[PS+5],cur[PS+5];struct edge {int to,nxt,F;}e[2*ES+5];
    	I void Add(CI x,CI y,CI f) {adde(x,y,f),adde(y,x,0);}
    	int q[PS+5],d[PS+5];I bool BFS() {RI i,k,H,T;for(i=1;i<=t;++i) d[i]=0;d[q[H=T=1]=s]=1;
    		W(H<=T&&!d[t]) for(i=lnk[k=q[H++]];i;i=e[i].nxt) !d[e[i].to]&&e[i].F&&(d[q[++T]=e[i].to]=d[k]+1);return d[t];}
    	I int DFS(CI x=s,RI f=1e9) {if(x==t||!f) return f;RI o,g=0;for(RI &i=cur[x];i;i=e[i].nxt)
    		if((d[x]+1)==d[e[i].to]&&(o=DFS(e[i].to,min(f,e[i].F)),e[i].F-=o,e[i^1].F+=o,g+=o,!(f-=o))) break;return g;}
    	I int MaxFlow() {RI g=0;W(BFS()) memcpy(cur,lnk,sizeof(lnk)),g+=DFS();return g;}
    	int p[PS+5];I void Topo()//反图拓扑
    	{
    		RI i,H=1,T=0;for(i=2;i<=ee;++i) !e[i].F&&++d[e[i].to];for(i=1;i<=n*m;++i) !d[i]&&(q[++T]=i);
    		RI k;W(H<=T) for(p[k=q[H++]]=1,i=lnk[k];i;i=e[i].nxt) !e[i].F&&!--d[e[i].to]&&(q[++T]=e[i].to);
    	}
    }
    int main()
    {
    	RI i,j,x,y,z;for(scanf("%d%d",&n,&m),i=1;i<=n*m;++i)
    		for(scanf("%d%d",a+i,&z);z;--z) scanf("%d%d",&x,&y),++x,++y,D::Add(P(x,y),i,INF);//攻击限制
    	for(i=1;i<=n;++i) for(j=1;j^m;++j) D::Add(P(i,j),P(i,j+1),INF);//位置限制
    	RI g=0;for(D::Topo(),i=1;i<=n*m;++i) D::p[i]&&(a[i]>0&&(D::Add(s,i,a[i]),g+=a[i]),a[i]<0&&(D::Add(i,t,-a[i]),0));//未删去的点与超级源汇连边
    	return printf("%d
    ",g-D::MaxFlow()),0;//总价值-最小割
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    [Algorithms] Insertion sort algorithm using TypeScript
    [Algorithms] Determine if a string is a palindrome
    [Algorithm] Determine if two strings are an anagram
    [Vue + TS] Watch for Changes in Vue Using the @Watch Decorator with TypeScript
    [Vue +TS] Use Two-Way Binding in Vue Using @Model Decorator with TypeScript
    uvc摄像头代码解析7
    并查集
    流程节点多场景多表单
    【图像识别】 图像处理和图像分析(leptonica)leptonica-1.68安装配置 (vs2008)
    Eclipse完美汉化教程
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2805.html
Copyright © 2011-2022 走看看