bzoj1565: [NOI2009]植物大战僵尸 最大权闭合子图,tarjan

bzoj1565: [NOI2009]植物大战僵尸

链接

https://www.lydsy.com/JudgeOnline/problem.php?id=1565

思路

很容易的想到最大权闭合子图
但这个图是有环的
有环的地方当然是都过不去的地方
显然他所保护的地方也是过不去的
他保护的地方的保护的地方也是过不去的
等等
还有这个这一行的[1,i]也是过不去的
tarjan之后递归判一下就行了

错误

好菜欧,调试了半天
其实我一开始以为环上就有了他所保护的地方
改了之后又没想到他保护的地方的保护的地方也是不可以过去的
好菜欧

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+7,M=107,inf=0x3f3f3f3f;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,m,S,T,Score[M][M],id[M][M];
vector<pair<int,int> > dsr[M][M];
bool mmp[M][M];
pair<int,int> kkk[M*M];
struct node {
    int u,v,nxt,cap;
}e[N];
int head[N],tot=1;
void add_edge(int u,int v,int cap) {
    e[++tot].u=u;
    e[tot].v=v;
    e[tot].cap=cap;
    e[tot].nxt=head[u];
    head[u]=tot;
}
void add(int u,int v,int cap) {
    add_edge(u,v,cap);
    add_edge(v,u,0);
}
int dis[N];
queue<int> q;
bool bfs() {
    memset(dis,-1,sizeof(dis));
    q.push(S);
    dis[S]=0;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v]==-1&&e[i].cap) {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    return dis[T]!=-1;
}
int dfs(int u,int f) {
    if(u==T) return f;
    int rest=f;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dis[v]==dis[u]+1&&e[i].cap&&rest) {
            int t=dfs(v,min(e[i].cap,rest));
            if(!t) dis[v]=0;
            e[i].cap-=t;
            e[i^1].cap+=t;
            rest-=t;
        }
    }
    return f-rest;
}
int dinic() {
    int ans=0;
    while(bfs())
        ans+=dfs(S,inf);
    return ans;
}
int dfn[N],low[N],stak[N],top,cnt,vis[N],belong[N];
vector<int> BE[N];
void tarjan(int u) {
    dfn[u]=low[u]=++cnt;
    vis[u]=1;
    stak[++top]=u;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(!e[i].cap) continue;
        if(!dfn[v]) {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        } else if(vis[v]) {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]) {
        belong[0]++;
        while(stak[top]!=u) {
            vis[stak[top]]=0;
            belong[stak[top]]=belong[0];
            BE[belong[0]].push_back(stak[top]);
            top--;
        } top--;
        vis[u]=0;
        BE[belong[0]].push_back(u);
        belong[u]=belong[0];
    }
}
void AC(int u) {
    if(mmp[kkk[u].first][kkk[u].second]) return;
    for(int k=1;k<=kkk[u].second;++k) mmp[kkk[u].first][k]=1;
    mmp[kkk[u].first][kkk[u].second]=1;
    for(vector<pair<int,int> >::iterator it=dsr[kkk[u].first][kkk[u].second].begin();it!=dsr[kkk[u].first][kkk[u].second].end();++it)
    // for(auto it : dsr[kkk[u].first][kkk[u].second])
        AC(id[it->first][it->second]);
}
int main() {
    n=read(),m=read();
    for(int i=1,js=0;i<=n;++i) { for(int j=1;j<=m;++j) {
        id[i][j]=++js;
        kkk[js]=make_pair(i,j);
    }}
    for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) {
        Score[i][j]=read();
        int gs=read();
        for(int k=1;k<=gs;++k) {
            int x=read()+1,y=read()+1;
            dsr[i][j].push_back(make_pair(x,y));
        }
        if(j>1)
        dsr[i][j].push_back(make_pair(i,j-1));
    }}
    S=n*m+1,T=n*m+2;
    for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) {
        for(vector<pair<int,int> >::iterator it=dsr[i][j].begin();it!=dsr[i][j].end();++it) {
            add(id[i][j],id[it->first][it->second],inf);
        }
    }}
    for(int i=1;i<=n*m;++i)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=tot;i++) {
        if(belong[e[i].u]==belong[e[i].v]) {
            AC(e[i].u);
        }
    }
    memset(head,0,sizeof(head));
    memset(e,0,sizeof(e));
    tot=1;
    for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) {
        if(mmp[i][j]==1) continue;
        if(j!=m&&mmp[i][j+1]!=1) add(id[i][j],id[i][j+1],inf);
        // for(auto it : dsr[i][j]) {
        for(vector<pair<int,int> >::iterator it=dsr[i][j].begin();it!=dsr[i][j].end();++it) {
            if(mmp[it->first][it->second]!=1)
            add(id[it->first][it->second],id[i][j],inf);
        }
    }}
    int sum=0;
    for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) {
        if(Score[i][j]>0&&!mmp[i][j]) sum+=Score[i][j];
        if(mmp[i][j]==1) continue;
        if(Score[i][j]>0) add(S,id[i][j],Score[i][j]);
        else add(id[i][j],T,-Score[i][j]);
    }}
    int ans=sum-dinic();
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/dsrdsr/p/10506199.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值