zoukankan      html  css  js  c++  java
  • 【NOI2009T4】植物大战僵尸-最大权闭合子图+拓补排序

    测试地址:植物大战僵尸

    做法:上次我们提到了最大权闭合子图的模型(见这里),这一个题目也容易看出是最大权闭合子图的模型,当一个植物被另一个植物保护的时候,隐含的关系就是:如果要选择攻击被保护植物,就必须也攻击保护植物,因此从被保护植物向保护植物连边,然后按照方法来建图求解。

    然而这还不够,在纯粹的求解最大权闭合子图的过程中,环要么就不取,要么就全部取走,而这一题的条件限定如果存在环一定不能取,进而指向环的所有点也不能取,那么怎么把这些点剔除掉呢?答案就是拓补排序。对原图的反图进行拓补排序,最后没有入过队的点就是不能取的点了,然后再跑最大流即可。

    以下是本人代码(注意!本人的代码会TLE,只能拿到90分,有待学习):

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #define inf 1000000000
    using namespace std;
    int n,m,first[1010]={0},tot=1;
    int level[1010],sum=0,val[1010],in[1010]={0};
    bool vis[1010]={0};
    struct edge {int v,f,next;} e[1000010];
    
    void insert(int a,int b,int f)
    {
      e[++tot].v=b,e[tot].f=f,e[tot].next=first[a],first[a]=tot;
      e[++tot].v=a,e[tot].f=0,e[tot].next=first[b],first[b]=tot;
    }
    
    void clear()
    {
      queue<int> q;
      for(int i=1;i<=n*m;i++)
        if (!in[i]) q.push(i);
      while(!q.empty())
      {
        int v=q.front();q.pop();
    	for(int i=first[v];i;i=e[i].next)
    	  if (e[i].v!=n*m+1&&e[i].v!=0&&!e[i].f)
    	  {
    	    in[e[i].v]--;
    		if (!in[e[i].v]) q.push(e[i].v);
          }
    	vis[v]=1;
      }
      
      for(int i=1;i<=n*m;i++)
        if (vis[i]&&val[i]>0) sum+=val[i];
    }
    
    bool makelevel()
    {
      queue<int> q;
      memset(level,0,sizeof(level));
      level[0]=1;
      q.push(0);
      
      while(!q.empty())
      {
        int v=q.front();q.pop();
    	for(int i=first[v];i;i=e[i].next)
    	  if (!level[e[i].v]&&e[i].f&&vis[e[i].v])
    	  {
    	    level[e[i].v]=level[v]+1;
    		q.push(e[i].v);
    	  }
      }
      
      return level[n*m+1];
    }
    
    int dfs(int v,int maxf)
    {
      int ret=0,f;
      if (v==n*m+1) return maxf;
      for(int i=first[v];i;i=e[i].next)
        if (level[e[i].v]==level[v]+1&&e[i].f&&vis[e[i].v])
    	{
    	  f=dfs(e[i].v,min(maxf-ret,e[i].f));
    	  e[i].f-=f;
    	  e[i^1].f+=f;
    	  ret+=f;
    	  if (ret==maxf) return ret;
    	}
      return ret;
    }
    
    int dinic()
    {
      int ans=0;
      while(makelevel())
      {
        ans+=dfs(0,inf);
      }
      return ans;
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1,b;i<=n*m;i++)
      {
        scanf("%d%d",&val[i],&b);
    	while(b--)
    	{
    	  int x,y;
    	  scanf("%d%d",&x,&y);
    	  insert(x*m+y+1,i,inf);
    	  in[x*m+y+1]++;
    	}
      }
      for(int i=0;i<n;i++)
        for(int j=0;j<m-1;j++)
    	{
    	  insert(i*m+j+1,i*m+j+2,inf);
    	  in[i*m+j+1]++;
        }
      clear();
      
      for(int i=1;i<=n*m;i++)
      {
        if (val[i]>0) insert(0,i,val[i]);
    	if (val[i]<0) insert(i,n*m+1,-val[i]);
      }
      
      vis[n*m+1]=1;
      printf("%d",sum-dinic());
      
      return 0;
    }


  • 相关阅读:
    Linux内核RPC请求过程
    二分图
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 文本加密
    Java蓝桥杯 算法提高 九宫格
    Java蓝桥杯 算法提高 九宫格
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793822.html
Copyright © 2011-2022 走看看