zoukankan      html  css  js  c++  java
  • 【BZOJ1565】【NOI2009】植物大战僵尸(网络流)

    【BZOJ1565】【NOI2009】植物大战僵尸(网络流)

    题面

    BZOJ
    洛谷

    题解

    做了这么多神仙题,终于有一道能够凭借自己智商能够想出来的题目了。。。。
    好感动。

    这就是一个比较裸的最小割模型。
    先考虑能够得到所有的正贡献,只需要减去所需的最小代价就可以了。
    考虑两个点保护与被保护的关系。
    强制要求如果选了被保护的点就必须选择保护的点
    那么从被保护的点向保护的点连(inf)边就好
    其他的随意选择源点或者汇点表示解决这个植物或者不解决
    然后对应的连边就好了。

    然而写完后发现连样例都过不了。
    因为有可能出现环,也就是一堆东西互相保护,导致都选不了
    所以先把图构出来,然后跑一下(Tarjan)缩环
    因为环上的点一定不能选,
    所以把环上的点的权值设为(-inf)就好了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 666
    #define inf 1e9
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Line{int v,next,w;}E[MAX*MAX],e[MAX*MAX*2];
    int h[MAX],cnt=2;
    int H[MAX],CNT=2;
    inline void Add(int u,int v,int w)
    {
    	e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
    	e[cnt]=(Line){u,h[v],0};h[v]=cnt++;
    }
    inline void Add(int u,int v){E[CNT]=(Line){v,H[u],0};H[u]=CNT++;}
    queue<int> Q;
    int n,m,bh[35][35],tot,W[MAX];
    int level[MAX],cur[MAX],S,T;
    bool bfs()
    {
    	for(int i=S;i<=T;++i)level[i]=0;
    	level[S]=1;Q.push(S);
    	while(!Q.empty())
    	{
    		int u=Q.front();Q.pop();
    		for(int i=h[u];i;i=e[i].next)
    			if(!level[e[i].v]&&e[i].w)
    				level[e[i].v]=level[u]+1,Q.push(e[i].v);
    	}
    	return level[T];
    }
    int dfs(int u,int flow)
    {
    	if(u==T||!flow)return flow;
    	int ret=0;
    	for(int &i=cur[u];i;i=e[i].next)
    	{
    		int v=e[i].v,d;
    		if(level[v]==level[u]+1&&e[i].w)
    		{
    			d=dfs(v,min(flow,e[i].w));
    			flow-=d;ret+=d;
    			e[i].w-=d;e[i^1].w+=d;
    			if(!flow)break;
    		}
    	}
    	if(!ret)level[u]=0;
    	return ret;
    }
    int Dinic()
    {
    	int ret=0;
    	while(bfs())
    	{
    		for(int i=S;i<=T;++i)cur[i]=h[i];
    		ret+=dfs(S,inf);
    	}
    	return ret;
    }
    int ans=0;
    int dfn[MAX],low[MAX],St[MAX],top,tim;
    bool ins[MAX];
    void Tarjan(int u)
    {
    	dfn[u]=low[u]=++tim;St[++top]=u;ins[u]=true;
    	for(int i=H[u];i;i=E[i].next)
    	{
    		int v=E[i].v;
    		if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
    		else if(ins[v])low[u]=min(low[u],dfn[v]);
    	}
    	if(dfn[u]==low[u])
    	{
    		if(St[top]==u)--top,ins[u]=false;
    		else
    		{
    			int v;
    			do{v=St[top--];ins[v]=false;W[v]=-inf;}while(u!=v);
    		}
    	}
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			bh[i][j]=++tot;
    	S=0;T=tot+1;
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    		{
    			W[bh[i][j]]=read();
    			if(j!=m)Add(bh[i][j+1],bh[i][j]);
    			int w=read();
    			while(w--)
    			{
    				int x=read()+1,y=read()+1;
    				Add(bh[i][j],bh[x][y]);
    			}
    		}
    	for(int i=1;i<=n*m;++i)if(!dfn[i])Tarjan(i);
    	for(int u=1;u<=n*m;++u)
    	{
    		if(W[u]>=0)ans+=W[u],Add(S,u,W[u]);
    		else Add(u,T,-W[u]);
    		for(int i=H[u];i;i=E[i].next)Add(E[i].v,u,inf);
    	}
    	printf("%d
    ",ans-Dinic());
    	return 0;
    }
    
    
  • 相关阅读:
    福利贴——爬取美女图片的Java爬虫小程序代码
    select多选 multiple的使用
    Android笔记---点击事件的四种写法
    二叉排序树的插入与删除
    hdu 5269 ZYB loves Xor I &amp;&amp; BestCoder Round #44
    linux 下同步异步,堵塞非堵塞的一些想法
    JavaScript编程随笔
    《从零開始学Swift》学习笔记(Day 51)——扩展构造函数
    What&#39;s Wrong With Hue Oozie Editor?
    2015.7个人反思小结以及兴许规划
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9189214.html
Copyright © 2011-2022 走看看