1. 程式人生 > >【[NOI2009]植物大戰僵屍】

【[NOI2009]植物大戰僵屍】

algo clas 就是 front n) math \n 一行 back

題目

我太\(zz\)

有一個非常顯然的問題就是一個植物顯然能保護同一行上比它更靠後的植物,因為顯然得先幹掉更靠前的植物

首先可以看出來這是一個經典的最大權閉合子圖的模型,於是去套最小割

發現植物的收益有正有負,於是想到正的和源點連邊,負的和匯點連邊

我們再來考慮一個植物沒有被割掉的的狀態

顯然是和源點的那條邊沒被割掉,所以這個植物應該向保護它的植物連邊,連代價為\(inf\)的邊,想要保留和源點的邊就必須去割掉這些連出去的邊指向的植物到匯點的邊

但是發現這樣連樣例都過不了

因為有一些植物非常神仙,自己保護自己,還有一些植物被神仙的植物保護,還有一些植物互相保護成了一個環

這些無敵的植物根本幹不掉,於是不能算到最大權閉合子圖裏

於是我們要搞一個拓撲排序,把環裏的點都給幹掉

之後連邊最小割就好了,記得把重邊去掉

代碼

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#define maxn 605
#define re register
#define LL long long
#define inf 999999999
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
struct E{int v,nxt,f,w;}e[maxn*maxn*2];
int n,m,S,T,num=1,ans,tot;
int head[maxn],d[maxn],cur[maxn];
int q[maxn],r[maxn],map[maxn][maxn];
std::vector<int> v[maxn];
std::vector<int> x[21][31],y[21][31];
int val[21][31],to[21][31];
inline void add(int x,int y,int z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;}
inline void C(int x,int y,int z) {add(x,y,z),add(y,x,0);}
inline char gc()
{
    static char buff[1000000],*S=buff,*T=buff;
    return S==T&&(T=(S=buff)+fread(buff,1,1000000,stdin),S==T)?EOF:*S++;
}
inline int read()
{
    char c=gc();int x=0,r=1;while(c<‘0‘||c>‘9‘) {if(c==‘-‘) r=-1;c=gc();}
    while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=gc();
    return x*r;
}
inline int BFS()
{
    std::queue<int> q;
    for(re int i=S;i<=T;i++) d[i]=0,cur[i]=head[i];
    d[S]=1,q.push(S);
    while(!q.empty())
    {
        int k=q.front();q.pop();
        for(re int i=head[k];i;i=e[i].nxt)
        if(!d[e[i].v]&&e[i].w>e[i].f) d[e[i].v]=d[k]+1,q.push(e[i].v);
    }
    return d[T];
}
int dfs(int x,int now)
{
    if(x==T||!now) return now;
    int ff,flow=0;
    for(re int& i=cur[x];i;i=e[i].nxt)
    if(d[e[i].v]==d[x]+1)
    {
        ff=dfs(e[i].v,min(now,e[i].w-e[i].f));
        if(ff<=0) continue;
        flow+=ff,now-=ff;
        e[i].f+=ff,e[i^1].f-=ff;
        if(!now) break;
    }
    return flow;
}
int main()
{
    n=read(),m=read();
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
        {
            val[i][j]=read();
            to[i][j]=(i-1)*m+j;
            if(j>1) v[to[i][j]].push_back(to[i][j-1]),r[to[i][j-1]]++;
            int t=read();int X,Y;
            for(re int k=0;k<t;k++) X=read()+1,Y=read()+1,x[i][j].push_back(X),y[i][j].push_back(Y);
        }
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
            for(re int k=0;k<x[i][j].size();k++)
            {
                int xx=x[i][j][k],yy=y[i][j][k];
                for(re int t=1;t<=yy;t++) r[to[xx][t]]++,v[to[i][j]].push_back(to[xx][t]);
            }
    for(re int i=1;i<=n;i++)    
        for(re int j=1;j<=m;j++)
            if(!r[to[i][j]]) q[++tot]=to[i][j];
    for(re int i=1;i<=tot;i++)
        for(re int j=0;j<v[q[i]].size();j++)
        {
            r[v[q[i]][j]]--;
            if(!r[v[q[i]][j]]) q[++tot]=v[q[i]][j];
        }
    S=0,T=n*m+1;
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
        {
            if(r[to[i][j]]) continue;
            if(val[i][j]<0) C(to[i][j],T,-1*val[i][j]);
                else C(S,to[i][j],val[i][j]),ans+=val[i][j];
            for(re int k=0;k<v[to[i][j]].size();k++) 
                if(!r[v[to[i][j]][k]]&&!map[v[to[i][j]][k]][to[i][j]]) 
                    map[v[to[i][j]][k]][to[i][j]]=1,C(v[to[i][j]][k],to[i][j],inf);
        }
    while(BFS()) ans-=dfs(S,inf);
    printf("%d\n",ans);
    return 0;
}

【[NOI2009]植物大戰僵屍】