P2805 [NOI2009]植物大战僵尸

总结

锅出的莫名其妙
首先是题目要求僵尸必须要从右边过来,也就是找拓扑序的时候必须要从每个点右边的点连一条边到这个点
然后是bfs的写法
如果这么写

int bfs(void){
    memset(vis,0,sizeof(vis));
    dep[s]=0;
    q.push(s);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        if(vis[x])//注意这里!!
            continue;//注意这里!!
        vis[x]=true;//注意这里!!
        for(int i=0;i<G[x].size();i++){
            Edge &e = edges[G[x][i]];
            if(e.cap>e.flow&&(!vis[e.v])){
                dep[e.v]=dep[x]+1;
                q.push(e.v);
            }
        }
    }
    return vis[t];
}

就会T飞
需要这样写

int bfs(void){
    memset(vis,0,sizeof(vis));
    dep[s]=0;
    q.push(s);
    vis[s]=1;//注意这里!!
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=0;i<G[x].size();i++){
            Edge &e = edges[G[x][i]];
            if(e.cap>e.flow&&(!vis[e.v])){
                dep[e.v]=dep[x]+1;
                vis[e.v]=true;//注意这里!!
                q.push(e.v);
            }
        }
    }
    return vis[t];
}

就跑的飞快,感觉像是没有保证一个节点只被入队一次造成复杂度不对了

思路

这题可以看出是一个最大权闭合子图的题目
但是有些点可能根本不可能被选到,所以先要拓扑一下,之后剩下的入度为0的节点就是可以选的,因为选择他们必然会有一个合法的拓扑序
然后注意僵尸只能从右边过来,所以一个点被选到之前,自己右边的点必须被选(拓扑的限制条件
然后就是最大权闭合子图的建模了
s向点权大于等于0的点连一条边权为点权的边,边权小于0的点向t连一条边权为点权绝对值的边,原图中的边不变,边权变成INF
最后正权的总和减去最小割就是答案了

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <ctime>
#include <cstdlib>
using namespace std;
const int MAXN = 1000;
const int INF = 0x3f3f3f3f;
const int MAXM = 400000;
int s,t;
inline int min(int a,int b){
    if(a<b)
        return a;
    else
        return b;
}
struct Edge{
    int u,v,cap,flow;
};
vector<Edge> edges;
vector<int> G[MAXN];
int cur[MAXN],vis[MAXN],dep[MAXN];
void addedge(int u,int v,int cap){
    edges.push_back((Edge){u,v,cap,0});
    edges.push_back((Edge){v,u,0,0});
    int cnt=edges.size();
    G[u].push_back(cnt-2);
    G[v].push_back(cnt-1);
}
int dfs(int x,int a){
    if(x==t||a==0)
        return a;
    int flow=0,f;
    for(int &i=cur[x];i<G[x].size();i++){
        Edge &e = edges[G[x][i]];
        if(dep[e.v]==dep[x]+1&&(f=dfs(e.v,min(a,e.cap-e.flow)))>0){
            flow+=f;
            e.flow+=f;
            edges[G[x][i]^1].flow-=f;
            a-=f;
            if(!a)
                break;
        }
    }
    return flow;
}

queue<int> q;
int bfs(void){
    memset(vis,0,sizeof(vis));
    dep[s]=0;
    q.push(s);
    vis[s]=1;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=0;i<G[x].size();i++){
            Edge &e = edges[G[x][i]];
            if(e.cap>e.flow&&(!vis[e.v])){
                dep[e.v]=dep[x]+1;
                vis[e.v]=true;
                q.push(e.v);
            }
        }
    }
    return vis[t];
}
int dinic(void){
    int flow=0;
    while(bfs()){
        memset(cur,0,sizeof(cur));
        flow+=dfs(s,INF);
    }
    return flow;
}
int in[MAXN],w_p[MAXN],Noden;
vector<int> to[MAXN];
void topu(void){
    for(int i=1;i<=Noden;i++)
        if(!in[i])
            q.push(i);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=0;i<to[x].size();i++){
            in[to[x][i]]--;
            if(!in[to[x][i]])
                q.push(to[x][i]);
        }
    }
}
int sum=0;
int n,m;
void build(void){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
        int x=(i-1)*m+j;
        if(in[x])
            continue;
        if(w_p[x]>=0)
            addedge(s,x,w_p[x]),sum+=w_p[x];
        else
            addedge(x,t,-w_p[x]);
        if(!in[x])
            for(int j=0;j<to[x].size();j++){
                if(!in[to[x][j]])
                    addedge(to[x][j],x,INF);
            }
    }
}
int main(){
    // freopen("testdata.in","r",stdin);
    scanf("%d %d",&n,&m);
    int s=clock();
    Noden=n*m;
    s=MAXN-2;
    t=MAXN-3;
    for(int i=1;i<=n;i++){
        for(int k=1;k<=m;k++){
        scanf("%d",&w_p[(i-1)*m+k]);
        int w;
        scanf("%d",&w);
        for(int j=1;j<=w;j++){
            int r,c;
            scanf("%d %d",&r,&c);
            // addedge((i-1)*m+k,r*m+c+1);
            to[(i-1)*m+k].push_back(r*m+c+1);
            in[r*m+c+1]++;
        }
        if(k<m){
            // addedge((i-1)*m+k+1,(i-1)*m+k);
            to[(i-1)*m+k+1].push_back((i-1)*m+k);
            in[(i-1)*m+k]++;
            }
        }
    }
    // printf("%lf
",1.0*clock()-s/CLOCKS_PER_SEC);
    topu();
        // printf("%lf
",1.0*clock()-s/CLOCKS_PER_SEC);
    build();
    // printf("%lf
",1.0*clock()-s/CLOCKS_PER_SEC);
    printf("%d
",sum-dinic());
        // printf("%lf
",1.0*clock()-s/CLOCKS_PER_SEC);
    return 0;
}
原文地址:https://www.cnblogs.com/dreagonm/p/10481995.html