zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    「Baltic2015」Network
    noip模拟赛 蒜头君的排序
    noip模拟赛 蒜头君的兔子
    codevs2171 棋盘覆盖
    noip模拟赛 蒜头君的坐骑
    noip模拟赛 蒜头君的树
    noip模拟赛 蒜头君打地鼠
    noip模拟赛 密码
    noip模拟赛 轰炸
    noip模拟赛 毁灭
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10481995.html
Copyright © 2011-2022 走看看