zoukankan      html  css  js  c++  java
  • 并不对劲的bzoj2521:p5039:[SHOI2010]最小生成树

    题目大意

    有一个(n)个点(m)条边的有边权的连通无向图,其中有一条边是被指定的。
    可以进行的操作是选一条边,把除它以外的边边权-1。
    问至少操作多少次,使被指定的边一定会在这张图的最小生成树上。
    (nleq 500;mleq800;边权leq10^6;)

    题解

    在进行最小生成树时,边权具体是多少不重要,重要的是边之间的边权大小关系。
    所以可以把“除某边以外的所有边边权-1”看成“该边边权+1”。
    从kruskal求最小生成树的过程中可以看出,只有当边权小于等于指定的边的边权的边不能让指定的边的端点连通时,指定的边才一定会加入最小生成树。
    也就是说,要通过最少的边权+1操作,使所有边权小于等于指定的边的边权的边不能让指定的边的端点连通。
    这可以用最小割解决。

    代码
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #define LL long long
    #define rep(i,x,y) for(int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(int i=(x);i>=(y);--i)
    #define view(u,k) for(int k=fir[u];~k;k=nxt[k])
    #define maxn 507
    #define maxm 3207 
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	char ch[20];int f=0;
    	if(!x){putchar('0'),putchar('
    ');return;}
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    }
    const int inf=2147483647;
    int fir[maxn],nxt[maxm],v[maxm],fl[maxm],cnte;
    int n,m,ss,tt,eu[maxm],ev[maxm],ew[maxm],lab,dis[maxn],maxfl,q[maxn],hd,tl; 
    void ade(int u1,int v1,int fl1)
    {
    	v[cnte]=v1,nxt[cnte]=fir[u1],fl[cnte]=fl1,fir[u1]=cnte++;
    	v[cnte]=u1,nxt[cnte]=fir[v1],fl[cnte]=0,fir[v1]=cnte++; 
    } 
    int getd()
    {
    	rep(i,1,n)dis[i]=-1;dis[ss]=0;q[hd=tl=1]=ss;
    	while(hd<=tl)
    	{
    		int u=q[hd];hd++;
    		view(u,k)if(fl[k]>0&&dis[v[k]]==-1){dis[v[k]]=dis[u]+1,q[++tl]=v[k];}
    	}
    	return dis[tt]==-1?0:1;
    }
    int getfl(int u,int nowfl)
    {
    	if(!nowfl||u==tt)return nowfl;
    	int tmp,sum=0;
    	view(u,k)
    	{
    		if(!nowfl)break;
    		if(fl[k]&&dis[v[k]]==dis[u]+1&&(tmp=getfl(v[k],min(nowfl,fl[k])))>0)
    			fl[k]-=tmp,fl[k^1]+=tmp,sum+=tmp,nowfl-=tmp;
    	}
    	return sum;
    }
    int main()
    {
    	n=read(),m=read(),lab=read();
    	rep(i,1,n)fir[i]=-1;
    	rep(i,1,m){eu[i]=read(),ev[i]=read(),ew[i]=read();if(i==lab)ss=eu[i],tt=ev[i];}
    	rep(i,1,m)if(i!=lab&&ew[i]<=ew[lab])
    	{
    		ade(eu[i],ev[i],ew[lab]-ew[i]+1);
    		ade(ev[i],eu[i],ew[lab]-ew[i]+1);
    	}
    	while(getd())maxfl+=getfl(ss,inf);
    	write(maxfl);
    	return (~(0-0)+1);
    }
    
  • 相关阅读:
    Marker
    Log4j 2
    Spring 中 CharacterEncodingFilter 失效?
    Java 泛型通配符
    待修 Bug
    Java Class SecurityManager
    bzoj 5210: 最大连通子块和【动态dp+树剖+线段树+堆】
    洛谷 P4719 【模板】动态dp【动态dp】
    bzoj 2555: SubString【后缀自动机+LCT】
    洛谷 P4125 [WC2012]记忆中的水杉树【扫描线+set+线段树】
  • 原文地址:https://www.cnblogs.com/xzyf/p/12984362.html
Copyright © 2011-2022 走看看