洛谷$P2805\ [NOI2009]$植物大战僵尸 网络流

正解:网络流

解题报告:

传送门$QwQ$

题面好长昂,,,我大概概括下$QwQ$?有个$n\cdot m$的网格,每个格子有一株植物,击溃一株植物$(x,y)$需要付出$S_{(x,y)}$的代价($S$可正可负.另外每株植物有$A_{(x,y)}$个可攻击位置,只要这株植物不死这些位置都是无法到达的$QwQ$.攻击规则是必须从右向左走,如果要攻击$(x,y)$位置的植物,需要把第$x$行在$y$右侧的所有植物都击溃才行$QwQ$

$umm$然后先考虑要击溃一株植物的前提$QwQ$?就说要击溃这株植物的话首先一定要击溃它右侧的那株植物和保护它的植物.那就是个最大权闭合子图问题?所以考虑最小割?

于是给$S_{(x,y)}$为正的点建一排点,为负的建一排点.分别和$S$,$T$连流量为$S_{x,y}$的绝对值的边.然后考虑边之间怎么连?发现就每个点向它右侧的那个点和保护它的点连个流量为$inf$的边就成$QwQ$

然后发现还有点儿问题?就说如果有互相保护的点就不能攻击,同时这两点保护的点也都不能攻击,可以先预处理把这些点直接不考虑$QwQ$.拓扑排序或者$tarjan$都成?因为我$tarjan$学得布星所以大概会用拓扑,$QwQ$

$over$

然后槽下自己码力,,,就明明实现不难,然后硬是打了几个小时,,,改了好久,,,

所以说,这里的拓扑排序建图要注意下,一定要想清楚了再打,我开始没想清楚就瞎打,发现$WA$了之后就再改,拆东墙补西墙的反而影响了思路,,,最后是重新理了遍思路重新打了遍才$AC$的,,,$QwQ$

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define n(i) edge[i].nxt
#define ri register int
#define rb register int
#define rc register char
#define t_tmp(i) edge_tmp[i].to
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define e(i,x) for(ri i=head[x];~i;i=n(i))
#define e_tmp(i,x) for(ri i=head_tmp[x];i;i=edge_tmp[i].nxt)

const int N=3000,M=50,inf=1e9;
int n,m,dep[N],head[N],cur[N],S,T,in[N],nam[M][M],nam_cnt,ed_cnt=-1,ed_tmp_cnt,head_tmp[N],s[N],sum;
bool vis[N];
vector<int>V[N];
struct ed{int to,nxt,wei;}edge[N<<2];
struct ed_tmp{int to,nxt;}edge_tmp[N*1000];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void ad(ri x,ri y,ri z)
{
    //printf("%d -> %d : %d\n",y,x,z);
    edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;edge[++ed_cnt]=(ed){y,head[x],0};head[x]=ed_cnt;
}
il void ad_tmp(ri x,ri y)
{edge_tmp[++ed_tmp_cnt]=(ed_tmp){x,head_tmp[y]};head_tmp[y]=ed_tmp_cnt;++in[x];}
il bool bfs()
{
    queue<int>Q;Q.push(S);memset(dep,0,sizeof(dep));dep[S]=1;
    while(!Q.empty()){ri nw=Q.front();Q.pop();/*printf("dep[%d]=%d\n",nw,dep[nw]);*/e(i,nw)if(w(i) && !dep[t(i)])dep[t(i)]=dep[nw]+1,Q.push(t(i));}
    return dep[T];
}
il int dfs(ri nw,ri flow)
{
    //printf("nw=%d flow=%d\n",nw,flow);
    if(nw==T || !flow)return flow;ri ret=0;
    for(ri &i=cur[nw];~i;i=n(i))
        if(w(i) && dep[t(i)]==dep[nw]+1){ri d=dfs(t(i),min(flow,w(i)));w(i)-=d,flow-=d,ret+=d,w(i^1)+=d;}
    return ret;
}
il int dinic(){ri ret=0;while(bfs()){/*printf("QwQ? dep[T]=%d\n",dep[T]);*/rp(i,S,T)cur[i]=head[i];while(int d=dfs(S,inf))ret+=d;}return ret;}
il void tpst()
{
    queue<int>Q;rp(i,S+1,T-1)if(!in[i])Q.push(i);
    while(!Q.empty())
    {
        ri nw=Q.front();vis[nw]=1;Q.pop();
        e_tmp(i,nw)
        {
            --in[t_tmp(i)];
            if(!in[t_tmp(i)])Q.push(t_tmp(i));
        }
    }
}

int main()
{
    //freopen("2805.in","r",stdin);freopen("2805.out","w",stdout);
    n=read();m=read();rp(i,1,n)rp(j,1,m)nam[i][j]=++nam_cnt;S=0;T=++nam_cnt;memset(head,-1,sizeof(head));
    rp(i,1,n)
    {
        rp(j,1,m)
        {
            if(j!=m)ad_tmp(nam[i][j],nam[i][j+1]),V[nam[i][j]].push_back(nam[i][j+1]);
            s[nam[i][j]]=read();ri tmp=read();
            rp(k,1,tmp){ri x=read()+1,y=read()+1;ad_tmp(nam[x][y],nam[i][j]);V[nam[x][y]].push_back(nam[i][j]);}
        }
    }
    tpst();
    rp(i,S+1,T-1)
    {
        if(!vis[i])continue;
        if(s[i]>0)ad(i,S,s[i]),sum+=s[i];else ad(T,i,-s[i]);
        ri sz=V[i].size();
        rp(j,0,sz-1)if(vis[V[i][j]])ad(V[i][j],i,inf);
    }
    printf("%d\n",sum-dinic());
    return 0;
}
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值