zoukankan      html  css  js  c++  java
  • 【洛谷4123】[CQOI2016] 不同的最小割(最小割树)

    点此看题面

    • 给定一张(n)个点(m)条边的无向图,询问所有点对间一共有多少种权值不同的最小割。
    • (nle850,mle8500)

    最小割树

    考虑最小割树的性质:任意两点(x,y)间的最小割就是最小割树上(x,y)间路径中的最小边权

    因此权值不同的最小割数实际上就是最小割树上权值不同的边数。

    具体实现中不需要真把树建出来,只要模拟建最小割树的过程,把所有边权加入一个(set)中即可。

    代码:(O(n^3m))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 850
    #define M 8500
    #define INF (int)1e9
    using namespace std;
    int n,m;set<int> S;
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    namespace D//网络流
    {
    	#define add(x,y,f) (_[++ee].nxt=lnk[x],_[lnk[x]=ee].to=y,_[ee].F=f)
    	int s,t,ee=1,lnk[N+5],cur[N+5];struct edge {int to,nxt,F;}e[2*M+5],_[2*M+5];
    	I void Add(CI x,CI y,CI f) {add(x,y,f),add(y,x,f);}
    	I void Init() {for(RI i=1;i<=ee;++i) e[i]=_[i];}
    	int q[N+5],d[N+5];I bool BFS() {RI i,k,H,T;for(i=1;i<=n;++i) d[i]=0;d[q[H=T=1]=s]=1;
    		W(H<=T&&!d[t]) for(i=lnk[k=q[H++]];i;i=e[i].nxt) !d[e[i].to]&&e[i].F&&(d[q[++T]=e[i].to]=d[k]+1);return d[t];}
    	I int DFS(CI x=s,RI f=1e9) {if(x==t||!f) return f;RI o,g=0;for(RI &i=cur[x];i;i=e[i].nxt)
    		if((d[x]+1)==d[e[i].to]&&(o=DFS(e[i].to,min(f,e[i].F)),e[i].F-=o,e[i^1].F+=o,g+=o,!(f-=o))) break;return g;}
    	I int MaxFlow() {RI g=0;W(BFS()) memcpy(cur,lnk,sizeof(lnk)),g+=DFS();return g;}
    }
    int id[N+5],idl[N+5],idr[N+5];I void Solve(CI l,CI r)//模拟建最小割树
    {
    	RI i,tl=0,tr=0;if(l>=r) return;D::Init(),D::s=id[l],D::t=id[r],S.insert(D::MaxFlow());//任取两点,把最小割加入set
    	for(i=l;i<=r;++i) (D::d[id[i]]?idl[++tl]:idr[++tr])=id[i];//根据最小割划分点集
    	for(i=1;i<=tl;++i) id[l+i-1]=idl[i];for(i=1;i<=tr;++i) id[l+tl+i-1]=idr[i];Solve(l,l+tl-1),Solve(l+tl,r);//递归求解
    }
    int main()
    {
    	RI i,x,y,z;for(read(n,m),i=1;i<=m;++i) read(x,y,z),D::Add(x,y,z);
    	for(RI i=1;i<=n;++i) id[i]=i;return Solve(1,n),printf("%d
    ",S.size()),0;//答案是最小割树上权值不同的边数
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    XXX系统讨论
    问题账户需求分析
    2017年秋季个人阅读计划
    《软件工程概论》的评价
    第二阶段Day10
    每周总结16
    假期学习记录13(ImageView实现动态加载网络图片)
    假期学习记录12(android与web服务器之间的list/json数组的消息传递)
    假期学习记录11(NavigationView点击事件无效)
    假期学习记录10(自定义AlertDialog,按钮关闭AlertDialog)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4123.html
Copyright © 2011-2022 走看看