zoukankan      html  css  js  c++  java
  • bzoj2893(费用流)

    先缩点,然后拆点,其实是很经典的一种操作,把不好做的点拆成边,然后我一开始想的是网络流,答案当然是增广次数,

    但可以发现跑网络流的话不同的跑法增广次数不一样,不太好找最小的。我们可以换一种神奇的思路,跑最大费用流,

    这样根据费用流每次都在最长路上增广保证每次都跑了尽量多的点,根据贪心原理可知这样是正确的。

    详见http://blog.csdn.net/iamzky/article/details/41846687;

    (一开始我一直错,发现自己增广用的dinic,模板打惯了就直接打上了。。。。忘了dinic是可以一次dfs实现多次增广的,没法统计增广次数。。我好蠢啊)

    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn=100010,inf=1e9;
    struct edg{
        int nxt,to,f,c;
    }e[maxn],g[maxn];
    int res,last[maxn],H[maxn],t1=1,t2=1,cas,dis[maxn],q[maxn],head,tail;
    void add1(int x,int y){
        ++t1;e[t1].nxt=last[x];last[x]=t1;e[t1].to=y;
    }
    void add2(int x,int y,int z,int zz){
        ++t2;g[t2].nxt=H[x];H[x]=t2;g[t2].to=y;g[t2].f=z;g[t2].c=zz;
        ++t2;g[t2].nxt=H[y];H[y]=t2;g[t2].to=x;g[t2].f=0;g[t2].c=-zz;
    }
    int scc,low[maxn],dfn[maxn],bel[maxn],cnt,sta[maxn],top,in[maxn];
    void tarjan(int x){
        low[x]=dfn[x]=++cnt;sta[++top]=x;in[x]=1;
        for(int i=last[x];i;i=e[i].nxt){
            int v=e[i].to;
            if(!dfn[v]){
                tarjan(v);low[x]=min(low[x],low[v]);
            }
            else{
                if(in[v])low[x]=min(low[x],dfn[v]);
            }
             
        }
        //cout<<"orz"<<endl;
        if(low[x]==dfn[x]){
            int now=0;scc++;
            while(now!=x){
                now=sta[top--];in[now]=0;
                bel[now]=scc;
            }
        }
    }
    struct dui{
        int from,to;
    }tmp[maxn];
    int pe[maxn],pv[maxn],mp[2010][2010],ans,vis[maxn],N,n,m,a,b,x,y,S,T,A[maxn],B[maxn],a1[maxn],b1[maxn];
    void solve(){
        while(1){
            memset(dis,-1,sizeof(dis));
            head=tail=0;q[++tail]=S;dis[S]=0;vis[S]=1;
            while(head!=tail){
                head=(head+1)%maxn;
                int u=q[head];
                for(int i=H[u];i;i=g[i].nxt){
                    int v=g[i].to;
                    if(g[i].f&&dis[v]<dis[u]+g[i].c){
                        dis[v]=dis[u]+g[i].c;
                        pe[v]=i;pv[v]=u;
                        if(!vis[v]){
                            vis[v]=1;tail=(tail+1)%maxn;
                            q[tail]=v;
                        }
                    }
                }
                vis[u]=0;
            }
            if(dis[T]<0)break;
            int mm=inf;
            for(int u=T;u!=S;u=pv[u])
            mm=min(mm,g[pe[u]].f);
            for(int u=T;u!=S;u=pv[u])
            g[pe[u]].f-=mm,g[pe[u]^1].f+=mm;
            res+=dis[T]*mm;
            if(dis[T]>0)
            ++ans;
        }
    }
    int main(){
        cin>>cas;
        while(cas--){
            memset(mp,0,sizeof(mp));
            memset(last,0,sizeof(last));
            memset(H,0,sizeof(H));
            memset(dfn,0,sizeof(dfn));
            cin>>n>>m>>a>>b;
            t1=t2=1;scc=cnt=0;
            for(int i=1;i<=a;++i){scanf("%d",&A[i]);}
            for(int i=1;i<=b;++i)scanf("%d",&B[i]);
            for(int i=1;i<=m;++i){
                scanf("%d%d",&tmp[i].from,&tmp[i].to);
                add1(tmp[i].from,tmp[i].to);
            }
            for(int i=1;i<=n;++i){
                if(!dfn[i])tarjan(i);
            }
            S=1;T=scc*2+2;
            for(int i=1;i<=n;++i){
                for(int j=last[i];j;j=e[j].nxt){
                    int u=bel[i],v=bel[e[j].to];
                    if(mp[u][v]||u==v)continue;
                    add2(u+scc+1,v+1,inf,0);
                    mp[u][v]=mp[v][u]=1;
                }
            }
            for(int i=1;i<=a;++i){
                add2(S,1+bel[A[i]],inf,0);
            }
            for(int i=1;i<=b;++i){
                add2(1+bel[B[i]]+scc,T,inf,0);
            }
            for(int i=1;i<=scc;++i){
                add2(1+i,1+scc+i,1,1);add2(1+i,1+scc+i,inf,0);
            }
            res=ans=0;solve();
            if(res!=scc)puts("no solution");
            else{printf("%d
    ",ans);}
        }
        //system("pause");
        return 0;
    }
    
  • 相关阅读:
    #虚树,树形dp#CF613D Kingdom and its Cities
    #搜索,容斥#洛谷 2567 [SCOI2010]幸运数字
    #三分#洛谷 5931 [清华集训2015]灯泡
    windows中日期自动替换
    oracle的tablespaces使用情况监控
    k8s配置master运行pod
    redis配置数据持久化
    Centos7清理僵尸进程
    ZOJ 1078 Palindrom Numbers
    OCP 071【中文】考试题库(cuug整理)第33题
  • 原文地址:https://www.cnblogs.com/dibaotianxing/p/8280913.html
Copyright © 2011-2022 走看看