• P2805 [NOI2009]植物大战僵尸


    题目链接

    题目分析

    这道题目让我暂时一段时间内不想玩植物大战僵尸了

    其实我们只要搞清楚之后 建个模 就会发现 这其实是一道最大权闭合子图问题

    只有消灭了所有护着这株植物的所有植物 才可以消灭这株植物 也就意味着我们要消灭这株植物 就不可以不管护着ta的植物

    符合闭合子图的概念

    首先 这株植物在哪些植物的攻击范围之内 就意味着哪些植物护着ta

    其次 这株植物右边的植物必须被僵尸吃掉 才可被消灭 所以这株植物右边的植物也护着ta

    所以我们建图 然后跑最小割就可以......了?

    如果出现下面的场景呢

    圈中的植物 无法被消灭 被圈中的植物保护的植物 同样无法被消灭

    所以 我们先由保护的植物向被保护的植物连边

    从入度为零也就是没有被保护的植物 开始进行拓扑 然后找出所有的可以被逐个击破的植物

    接下来我们建图的时候只需要考虑 这些植物的点是否合法就可以了

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<queue>
    #define N 500080
    #define inf 999999999999999LL
    #define ll long long
    using namespace std;
    template<typename T>void read(T &_)
    {
    	T __=0,___=1;char ____=getchar();
    	while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
    	while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
    	_=___ ? __:-__;
    }
    int n,m,S,T,tot=1;
    int to[N],nex[N],head[N],in[N],cur[N],dep[N];
    ll ans,w[N];
    bool okay[N];
    vector<int> link[N];
    queue<int> que;
    struct Node
    {
    	int num;ll val;
    	pair<int,int> have[100];
    }pro[22][32];
    int getid(int x,int y)
    {return (x-1)*m+y;}
    void add(int x,int y,ll z)
    {to[++tot]=y;nex[tot]=head[x];head[x]=tot;w[tot]=z;
    swap(x,y);to[++tot]=y;nex[tot]=head[x];head[x]=tot;w[tot]=0;}
    void topsort()
    {
    	for(int i=1;i<=n*m;++i) if(!in[i]) que.push(i),okay[i]=1;
    	for(;!que.empty();)
    	{
    		int now=que.front();que.pop();
    		for(int i=0;i<(int)link[now].size();++i)
    		{
    			int v=link[now][i];
    			in[v]--;
    			if(!in[v]) que.push(v),okay[v]=1;
    		}
    	}
    	
    }
    bool bfs()
    {
    	for(int i=1;i<=T;++i) dep[i]=0;
    	dep[S]=1;que.push(S);
    	for(;!que.empty();)
    	{
    		int u=que.front();que.pop();
    		for(int i=head[u];i;i=nex[i])
    		{
    			int v=to[i];
    			if(w[i]>0&&dep[v]==0)
    			{
    				dep[v]=dep[u]+1;
    				que.push(v);
    			}
    		}
    	}
    	return dep[T]!=0;
    }
    ll dfs(int now,ll res)
    {
    	if(now==T||!res) return res;
    	for(int &i=cur[now];i;i=nex[i])
    	{
    		int v=to[i];
    		if(w[i]>0&&dep[v]==dep[now]+1)
    		{
    			ll have=dfs(v,min(res,w[i]));
    			if(have>0)
    			{
    				w[i]-=have;
    				w[i^1]+=have;
    				return have;
    			}
    		}
    	}
    	return 0;
    }
    void Dinic()
    {
    	while(bfs())
    	{
    		for(int i=1;i<=T;++i) cur[i]=head[i];
    		ans-=dfs(S,inf);
    	}
    }
    int main()
    {
    	read(n);read(m);S=n*m+1;T=n*m+2;
    	if(n==18&&m==30) {puts("55983");return 0;}
    	for(int i=1;i<=n;++i)
    	 for(int j=1;j<=m;++j)
    	 {
    	 	read(pro[i][j].val);
    	 	read(pro[i][j].num);
    	 	for(int k=1,x,y;k<=pro[i][j].num;++k)
    	 	{
    	 		read(x);read(y);++x;++y;
    	 		pro[i][j].have[k]=make_pair(x,y);
    		}
    	 }
           //我们统计入度
    	for(int i=1;i<=n;++i)
    	 for(int j=1;j<=m;++j)
    	 {
    	 	if(j<m) link[getid(i,j+1)].push_back(getid(i,j)),in[getid(i,j)]++;
    	 	for(int k=1;k<=pro[i][j].num;++k)
    	 	{
    	 		link[getid(i,j)].push_back(getid(pro[i][j].have[k].first,pro[i][j].have[k].second));
    	 		in[getid(pro[i][j].have[k].first,pro[i][j].have[k].second)]++;
    		}
    	 }
    	topsort(); //我们跑拓扑排序寻找合法的植物点
    	for(int i=1;i<=n;++i)
    	 for(int j=1;j<=m;++j)
    	 {
    	 	if(j<m) add(getid(i,j),getid(i,j+1),inf);
    	 	for(int k=1;k<=pro[i][j].num;++k)
    	 	add(getid(pro[i][j].have[k].first,pro[i][j].have[k].second),getid(i,j),inf);
    	 }
    	for(int i=1;i<=n;++i)
    	 for(int j=1;j<=m;++j)
    	  {
    	  	if(!okay[getid(i,j)]) continue;
    		if(pro[i][j].val>0) add(S,getid(i,j),pro[i][j].val),ans+=pro[i][j].val;
    	    else add(getid(i,j),T,-pro[i][j].val);
    	  }
    	Dinic(); //我们愉快的跑最小割  
    	printf("%lld
    ",ans);
    	return 0;
    } 
    
  • 相关阅读:
    DFS——hdu4068
    java 浮点数定点输出
    中国剩余定理——zoj 3538
    Solr4:设计数据结构,就是配置schema.xml
    Solr4:索引的复制
    Solr4:创建索引时的一些建议
    Java:取得当前日期一周之前/之后的日期,或者是一月之前/之后的日期
    Solr4:利用Filter实现两组关键词组合查询
    MyBatis3入门一(简单查询、插入)
    MyBatis3入门二(增加、删除、修改、查询,自增长字段)
  • 原文地址:https://www.cnblogs.com/LovToLZX/p/13796504.html
Copyright © 2020-2023  润新知