zoukankan      html  css  js  c++  java
  • Destroying The Graph(poj 2125)

    题意:

    给你一张有向图,你可以选择一个点:
    • 摧毁其所有的入边,代价A[i].
    • 摧毁其所有的出边,代价B[i].
    • 求摧毁这张图的最小代价。
    • 数据范围1000

    /*
      很经典的一道题目(我这么弱,稍微一变形就不会了)
      因为每个点涉及到出边和入边,所以可以考虑拆点,然后建图,接下来就成了一个最小点权覆盖的问题。
      最小点权覆盖就是求最小割(证明可参考胡伯涛论文“最小割模型在信息学竞赛中的应用”)。
      接下来是输出方案,因为我们要选择的点与S或T连得边是满流的,所以可以dfs一边,只走不满流的,
      那么如果一个<=n的点走不到,说明它被选择了(这个很好理解),如果一个>n的点能走到,说明它被选择了, 
      这是因为如果这个点没有被选择,说明从前面水流流过来的时候到某个位置已经割断了,在这里就没必要再割了。 
      (貌似好难理解的样子,我这么弱肯定想不出来)。 
    */
    #include<cstdio>
    #include<iostream>
    #define N 210
    #define M 5010
    #define inf 1000000000
    using namespace std;
    int a[N],b[N],head[N],dis[N],q[N],vis[N],n,m,cnt=1,S,T;
    struct node{
        int v,f,pre;
    };node e[M*2];
    void add(int u,int v,int f){
        e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt;
        e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt;
    }
    bool bfs(){
        for(int i=1;i<=T;i++)dis[i]=inf;
        int h=0,t=1;q[1]=S;dis[S]=0;
        while(h<t){
            int u=q[++h];
            for(int i=head[u];i;i=e[i].pre){
                int v=e[i].v;
                if(e[i].f&&dis[u]+1<dis[v]){
                    dis[v]=dis[u]+1;
                    if(v==T)return true;
                    q[++t]=v;
                }
            }
        }
        if(dis[T]==inf)return false;
        return true;
    }
    int dinic(int now,int f){
        if(now==T)return f;
        int rest=f;
        for(int i=head[now];i;i=e[i].pre){
            int v=e[i].v;
            if(e[i].f&&dis[v]==dis[now]+1){
                int t=dinic(v,min(rest,e[i].f));
                if(!t)dis[v]=0;
                e[i].f-=t;
                e[i^1].f+=t;
                rest-=t;
            }
        }
        return f-rest;
    }
    void dfs(int x){
        vis[x]=1;
        for(int i=head[x];i;i=e[i].pre){
            if(!e[i].f||vis[e[i].v])continue;
            dfs(e[i].v);
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        S=0,T=2*n+1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            add(i+n,T,a[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&b[i]);
            add(S,i,b[i]);
        }
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
            add(x,y+n,inf);
        }
        int min_cnt=0,p=0,pin=0,pout=0;
        while(bfs()) min_cnt+=dinic(S,inf);
        printf("%d
    ",min_cnt);
        dfs(S);
        for(int i=1;i<=n;i++){
            if(!vis[i])p++;
            if(vis[i+n])p++;
        }
        printf("%d
    ",p);
        for(int i=1;i<=n;i++){
            if(!vis[i])printf("%d -
    ",i);
            if(vis[i+n])printf("%d +
    ",i);
        }
        return 0;
    }
  • 相关阅读:
    Java
    Java
    Java
    其他
    Java
    Java
    Java
    正则
    Win10
    【转】Flask 上下文机制和线程隔离
  • 原文地址:https://www.cnblogs.com/harden/p/6257816.html
Copyright © 2011-2022 走看看