【BZOJ 1565】[NOI2009]植物大战僵尸

题目描述

输入

输出

仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

样例输入

3 2

10 0

20 0

-10 0

-5 1 0 0

100 1 2 1

100 0

样例输出

25

。。一看就是一个网络流,首先有两种植物,一种有收益,一种需花费。
我们可以尝试着想到最小割,先统计出总收益tot(所有收益之和),在想办法构造出一个图,
使得它的每一个割对应:不要的收益+所花的花费 。那么这时,答案就等于 tot-最小割。
至于怎么构图,我们可以吧最小割割开的图看做S->T集(即和源或汇点分在一个集合中的点集)
S集中的点一定是被吃掉的植物,相反,T中就是没有被吃的。
于是,我们考虑将收益和花费的植物分别将S,T连边,有因为僵尸是从左向右吃的,要想吃掉一棵植物必须吃掉保护他的那棵植物,对于这样的拓扑关系,很明显要先将先被吃的那棵植物划分到S集,也就是将他和T的连边断掉,于是对于每一点,我们向在拓扑关系中的他上一层的节点连一条为INF的边。
不过这里要注意,当拓扑关系中存在环时,在流网络中就形成了一个INF的环路,最小割割掉的一定是环路与S,T的所有边,那么这就错了。
于是我们必须预处理拓扑关系图中的所有环路,将所有不可能到达的点删去,再构图跑网络流,这里JeremyGuo提供了一个很方便的解决方案:我们对于原图中的每一个强联通分量都从中找出一个点,将其与T连一条INF边,那么这个强连通分量就一定属于T集合,于是就只算了不需要的收益。至于找点向T连边,这个有很多搞法,而且又不是一个分量只能连一条,所以乱搞搞就行了。

/**************************************************************
    Problem: 1565
    User: szpszp
    Language: C++
    Result: Accepted
    Time:188 ms
    Memory:29440 kb
****************************************************************/

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

#define MAXN 20
#define MAXM 30
#define INF 0x3f3f3f3f
typedef long long int LL;

template<class T>
void Read(T &x){
    x=0;char c=getchar();bool flag=0;
    while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    if(flag)x=-x;
}

namespace ISAP{
    const int MAXP = MAXN*MAXM;
    const int MAXE = MAXN*MAXM*MAXN*MAXM*2;

    struct node{
        int v,c;
        node *nxt,*bck;
    }*adj[MAXP+10],Edges[MAXE*2+100],*New;

    int d[MAXP+10],vd[MAXP+10];
    int S,T,P;

    void addedges(int u,int v,int c){
        node *p=++New;
        p->v=v;
        p->c=c;
        p->nxt=adj[u];
        p->bck=New+1;
        adj[u]=p;

        p=++New;
        p->v=u;
        p->c=0;
        p->nxt=adj[v];
        p->bck=New-1;
        adj[v]=p;
    }

    void init(int s,int t,int p){
        S=s,T=t,P=p;
        memset(adj,0,sizeof(adj));
        New=Edges;
    }

    int aug(int x,int augco){
        if(x==T)return augco;
        int Dmin=P-1,augc=augco,delta;

        for(node *p=adj[x];p!=NULL;p=p->nxt)
            if(p->c){
                if(d[x]==d[p->v]+1){
                    delta=min(augc,p->c);
                    delta=aug(p->v,delta);
                    p->c-=delta;
                    p->bck->c+=delta;
                    augc-=delta;

                    if(d[S]>=P)
                        return augco-augc;
                    if(!augc)
                        break;
                }

                Dmin=min(Dmin,d[p->v]);
            }

        if(augco==augc){
            if(!(--vd[d[x]]))
                d[S]=P;
            ++vd[d[x]=Dmin+1];
        }

        return augco-augc;
    }

    int isap(){
        memset(d,0,sizeof(d));
        memset(vd,0,sizeof(vd));
        vd[0]=P;

        int flow=0;
        while(d[S]<P)
            flow+=aug(S,INF);
        return flow;
    }
}

int w[MAXN+10][MAXM+10];
int n,m;

int id[MAXN+10][MAXM+10],tot;
void makeid(int n,int m){
    tot=0;
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j)
            id[i][j]=++tot;
}

struct node{
    int v;
    node *nxt;
}*adj[MAXN*MAXM+10],Edges[MAXN*MAXM*MAXN*MAXM*2+100],*New=Edges;

void addedge(int u,int v){
    node *p=++New;
    p->v=v;
    p->nxt=adj[u];
    adj[u]=p;
}

bool vis[MAXN*MAXM+10],tag[MAXN*MAXM+10];
vector<int>point;
void dfs(int x){
    vis[x]=tag[x]=1;
    for(node *p=adj[x];p!=NULL;p=p->nxt){
        if(!vis[p->v])dfs(p->v);
        else if(tag[p->v])point.push_back(p->v);
    }

    tag[x]=0;
}

int main(){
    Read(n),Read(m);
    makeid(n,m);

    int t,x,y;
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j){
            Read(w[i][j]);
            Read(t);
            for(int k=0;k<t;++k){
                Read(x),Read(y);
                addedge(id[i][j],id[x][y]);
            }
        }
    for(int i=0;i<n;++i)
        for(int j=1;j<m;++j)addedge(id[i][j],id[i][j-1]);

    for(int i=1;i<=tot;++i)
        if(!vis[i])dfs(i);

    ISAP::init(tot+1,tot+2,tot+2);
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j){
            if(w[i][j]>=0){
                ISAP::addedges(ISAP::S,id[i][j],w[i][j]);
                //ISAP::addedges(id[i][j],ISAP::T,0);
            }
            else{
                //ISAP::addedges(ISAP::S,id[i][j],0);
                ISAP::addedges(id[i][j],ISAP::T,-w[i][j]);
            }

            for(node *p=adj[id[i][j]];p!=NULL;p=p->nxt)
                ISAP::addedges(p->v,id[i][j],INF);
        }

    for(int i=0;i<point.size();++i)
        ISAP::addedges(point[i],ISAP::T,INF);

    int ans=0;
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j)
            if(w[i][j]>0)ans+=w[i][j];

    printf("%d\n",ans-ISAP::isap());
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VR(Virtual Reality)即虚拟现实,是一种可以创建和体验虚拟世界的计算机技术。它利用计算机生成一种模拟环境,是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真,使用户沉浸到该环境中。VR技术通过模拟人的视觉、听觉、触觉等感觉器官功能,使人能够沉浸在计算机生成的虚拟境界中,并能够通过语言、手势等自然的方式与之进行实时交互,创建了一种适人化的多维信息空间。 VR技术具有以下主要特点: 沉浸感:用户感到作为主角存在于模拟环境中的真实程度。理想的模拟环境应该使用户难以分辨真假,使用户全身心地投入到计算机创建的三维虚拟环境中,该环境中的一切看上去是真的,听上去是真的,动起来是真的,甚至闻起来、尝起来等一切感觉都是真的,如同在现实世界中的感觉一样。 交互性:用户对模拟环境内物体的可操作程度和从环境得到反馈的自然程度(包括实时性)。例如,用户可以用手去直接抓取模拟环境中虚拟的物体,这时手有握着东西的感觉,并可以感觉物体的重量,视野中被抓的物体也能立刻随着手的移动而移动。 构想性:也称想象性,指用户沉浸在多维信息空间中,依靠自己的感知和认知能力获取知识,发挥主观能动性,寻求解答,形成新的概念。此概念不仅是指观念上或语言上的创意,而且可以是指对某些客观存在事物的创造性设想和安排。 VR技术可以应用于各个领域,如游戏、娱乐、教育、医疗、军事、房地产、工业仿真等。随着VR技术的不断发展,它正在改变人们的生活和工作方式,为人们带来全新的体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值