zoukankan      html  css  js  c++  java
  • BZOJ 3118 Orz the MST

    权限题qwq

    如果我们要使得某棵生成树为最小生成树,那么上面的边都不能被替代,具体的,对于一个非树边,它的权值要(ge)它两端点在树上的路径上的所以边的权值,所以对于每个非树边就可以对一些树边列出不等关系,并且显然要把树边减小边权,非树边增加边权才会更优,所以记树边减少量为(dt_a),非树边增加量为(dt_b),就可以改写成不等式(dt_a+dt_bge max(w_a-w_b,0)).那么问题变成若干变量,每个变量每增加(1)要付出一定代价,求最小代价满足所有不等式

    这个不等式的形式有点不好下手,考虑这个问题的对偶问题,这等价于对于每个不等式(i)确定一个非负权值,每有一个权值获得(max(w_a-w_b,0))的收益,同时满足权值(le)对应树边和非树边修改一次的代价,求最大收益.那么可以网络流解决,(S)向所有树边连容量/费用为((c_a,0))的边,非树边向(T)((c_b,0))的边,有不等式关系的一组边连((+infty,max(w_a-w_b,0)))的边,然后最大费用流即可

    #include<bits/stdc++.h>
    #define LL long long
    #define uLL unsigned long long
    #define db double
    
    using namespace std;
    const int N=2000+10,M=N*100,inf=1<<30;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int to[M],nt[M],c[M],w[M],hd[N],tot=1;
    void add(int x,int y,int z,int zz)
    {
        ++tot,to[tot]=y,nt[tot]=hd[x],c[tot]=z,w[tot]=zz,hd[x]=tot;
        ++tot,to[tot]=x,nt[tot]=hd[y],c[tot]=0,w[tot]=-zz,hd[y]=tot;
    }
    int ps,pt,di[N],fw[N],pr[N],cst;
    bool v[N];
    queue<int> q;
    bool csfl()
    {
        for(int i=0;i<=pt;++i) di[i]=inf;
        di[ps]=0,fw[ps]=inf,fw[pt]=0,v[ps]=1,q.push(ps);
        while(!q.empty())
        {
        	int x=q.front();
        	q.pop();
        	for(int i=hd[x];i;i=nt[i])
        	{
        	    int y=to[i];
        	    if(c[i]>0&&di[y]>di[x]+w[i])
        	    {
            		di[y]=di[x]+w[i];
            		fw[y]=min(fw[x],c[i]),pr[y]=i;
            		if(!v[y]) v[y]=1,q.push(y);
        	    }
        	}
        	v[x]=0;
        }
        if(!fw[pt]||di[pt]>=0) return 0; //边权取反做最大费用流,增广的权值不优就停止
        cst+=di[pt]*fw[pt];
        int x=pt;
        while(x!=ps)
        {
        	int i=pr[x];
        	c[i]-=fw[pt],c[i^1]+=fw[pt];
        	x=to[i^1];
        }
        return 1;
    }
    int n,m,ee[N][2],ew[N],cs[N],fa[N],pre[N],de[N];
    bool fg[N];
    void dd(int x)
    {
        for(int i=hd[x];i;i=nt[i])
        {
        	int y=to[i];
        	if(y==fa[x]) continue;
        	if(fg[i>>1]) fa[y]=x,pre[y]=i>>1,de[y]=de[x]+1,dd(y);
        }
    }
    void link(int i,int j)
    {
        int ss=max(0,ew[i]-ew[j]);
        add(i,j,inf,-ss);
    }
    
    int main()
    {
        freopen("3118.in","r",stdin);
        freopen("3118.out","w",stdout);
        n=rd(),m=rd();
        for(int i=1;i<=m;++i)
        {
        	int x=rd(),y=rd();
        	add(ee[i][0]=x,ee[i][1]=y,0,0);
        	ew[i]=rd(),fg[i]=rd();
        	if(fg[i]) rd(),cs[i]=rd();
        	else cs[i]=rd(),rd();
        }
        de[1]=1,dd(1);
        memset(hd,0,sizeof(int)*(n+3)),tot=1;
        ps=0,pt=m+2;
        for(int i=1;i<=m;++i)
        {
        	if(fg[i]) add(ps,i,cs[i],0);
        	else
        	{
        	    add(i,pt,cs[i],0);
        	    int x=ee[i][0],y=ee[i][1];
        	    if(de[x]<de[y]) swap(x,y);
        	    while(de[x]>de[y]) link(pre[x],i),x=fa[x];
        	    while(x!=y)
        	    {
            		link(pre[x],i),x=fa[x];
            		link(pre[y],i),y=fa[y];
        	    }
        	}
        }
        while(csfl());
        printf("%d
    ",-cst);
        return 0;
    }
    
  • 相关阅读:
    Python在程序中进行多任务操作-协程
    Python-异常处理
    Python多任务-协程
    【每日一具4】TikTok 抖音国际版(网站)使用起来非常简单,无需FQ随便看
    【每日一具3】优美APP一款好用的短视频软件,优美APP专注于各种小姐姐短视频
    Python在程序中进行多任务操作-线程
    Python在程序中进行多任务操作-进程
    Python多任务-线程
    Python多任务-进程
    【每日一具3】优美APP一款好用的短视频软件,优美APP专注于各种小姐姐短视频
  • 原文地址:https://www.cnblogs.com/smyjr/p/11247017.html
Copyright © 2011-2022 走看看