zoukankan      html  css  js  c++  java
  • 【BZOJ2561】最小生成树 最小割

    【BZOJ2561】最小生成树

    Description

     给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?

    Input

      第一行包含用空格隔开的两个整数,分别为N和M;
      接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
      最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
      数据保证图中没有自环。

    Output

     输出一行一个整数表示最少需要删掉的边的数量。

    Sample Input

    3 2
    3 2 1
    1 2 3
    1 2 2

    Sample Output

    1

    HINT

    对于20%的数据满足N ≤ 10,M ≤ 20,L ≤ 20;
      对于50%的数据满足N ≤ 300,M ≤ 3000,L ≤ 200;
      对于100%的数据满足N ≤ 20000,M ≤ 200000,L ≤ 20000。

    题解:回忆Kruskal的过程,如果只用边权<L的点,u和v就能连通,那么(u,v)一定不再最小生成树上。所以,我们只保留边权<L的点,跑u->v的最小割即可。

    最大生成树同理。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    using namespace std;
    int S,T,L,n,m,cnt,ans;
    
    int head[20010],next[800010],val[800010],to[800010],d[20010],pa[200010],pb[200010],len[200010];
    queue<int> q;
    
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int dfs(int x,int mf)
    {
    	if(x==T)	return mf;
    	int i,k,temp=mf;
    	for(i=head[x];i!=-1;i=next[i])
    	{
    		if(d[to[i]]==d[x]+1&&val[i])
    		{
    			k=dfs(to[i],min(temp,val[i]));
    			if(!k)	d[to[i]]=0;
    			val[i]-=k,val[i^1]+=k,temp-=k;
    			if(!temp)	break;
    		}
    	}
    	return mf-temp;
    }
    int bfs()
    {
    	memset(d,0,sizeof(d));
    	while(!q.empty())	q.pop();
    	int i,u;
    	d[S]=1,q.push(S);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=next[i])
    		{
    			if(!d[to[i]]&&val[i])
    			{
    				d[to[i]]=d[u]+1;
    				if(to[i]==T)	return 1;
    				q.push(to[i]);
    			}
    		}
    	}
    	return 0;
    }
    void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i;
    	for(i=1;i<=m;i++)	pa[i]=rd(),pb[i]=rd(),len[i]=rd();
    	S=rd(),T=rd(),L=rd();
    	memset(head,-1,sizeof(head)),cnt=0;
    	for(i=1;i<=m;i++)	if(len[i]<L)	add(pa[i],pb[i],1),add(pb[i],pa[i],1);
    	while(bfs())	ans+=dfs(S,1<<30);
    	memset(head,-1,sizeof(head)),cnt=0;
    	for(i=1;i<=m;i++)	if(len[i]>L)	add(pa[i],pb[i],1),add(pb[i],pa[i],1);
    	while(bfs())	ans+=dfs(S,1<<30);
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    编程时候底层函数的来源
    (转)线程相关的东东
    (转)CreateThread与_beginthread,内存泄漏为何因(原帖排版有些不好 ,所以我稍微整理下)
    测试CDockablePane。 测试他的最基本的功能。
    (转)单例模式(Singleton)的常见应用场景
    (转)http 之session和cookie
    Palindrome Linked List
    Basic Calculator II
    (转)外部排序
    (转)eclipse调试java程序的九个技巧
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7297668.html
Copyright © 2011-2022 走看看