bzoj4519: [Cqoi2016]不同的最小割(最小割树)

时间:2022-03-15 04:28:43

传送门

 

好神仙……最小割树是个什么东西……

其实我觉得干脆直接$O(n^2)$跑几个dinic算了……

来说一下这个叫最小割树的神奇东西

我们先建一个$n$个点,没有边的无向图

在原图中任选两点$s,t$,然后跑一遍最小割。那么在残量网络上的点会分成两个集合,一个属于$s$,一个属于$t$

我们在无向图中连接$s,t$两点,边权为最小割

然后分别对$s$的点集和$t$的点集递归做以上过程,直到生成一棵树

那么原图中任意两点的最小割就是他们树上路径的最小值

证明?(能用就好要什么证明)

感性理解一下吧……

因为题目只要求不同的最小割的个数

那么只要用一个set存一下就好了

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<set>
 7 #include<queue>
 8 #define inf 0x3f3f3f3f
 9 using namespace std;
10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
11 char buf[1<<21],*p1=buf,*p2=buf;
12 inline int read(){
13     #define num ch-'0'
14     char ch;bool flag=0;int res;
15     while(!isdigit(ch=getc()))
16     (ch=='-')&&(flag=true);
17     for(res=num;isdigit(ch=getc());res=res*10+num);
18     (flag)&&(res=-res);
19     #undef num
20     return res;
21 }
22 const int N=1005,M=20005;
23 int head[N],Next[M],ver[M],edge[M],ee[M],tot=1;
24 int dep[N],cur[N],vis[N],n,m,s,t;
25 queue<int> q;set<int> S;
26 inline void add(int u,int v,int e){
27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=ee[tot]=e;
28     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=ee[tot]=e;
29 }
30 inline void clear(){
31     for(int i=2;i<=tot;++i) edge[i]=ee[i];
32 }
33 bool bfs(){
34     while(!q.empty()) q.pop();
35     for(int i=1;i<=n;++i) cur[i]=head[i];
36     memset(dep,-1,sizeof(dep));
37     q.push(s),dep[s]=0;
38     while(!q.empty()){
39         int u=q.front();q.pop();
40         for(int i=head[u];i;i=Next[i]){
41             int v=ver[i];
42             if(dep[v]<0&&edge[i]){
43                 dep[v]=dep[u]+1,q.push(v);
44                 if(v==t) return true;
45             }
46         }
47     }
48     return false;
49 }
50 int dfs(int u,int limit){
51     if(u==t||!limit) return limit;
52     int flow=0,f;
53     for(int i=cur[u];i;cur[u]=i=Next[i]){
54         int v=ver[i];
55         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
56             flow+=f,limit-=f;
57             edge[i]-=f,edge[i^1]+=f;
58             if(!limit) break;
59         }
60     }
61     return flow;
62 }
63 int dinic(){
64     int flow=0;
65     while(bfs()) flow+=dfs(s,inf);
66     return flow;
67 }
68 void find(int u){
69     vis[u]=1;
70     for(int i=head[u];i;i=Next[i]){
71         int v=ver[i];
72         if(!vis[v]&&edge[i]) find(v);
73     }
74 }
75 void check(){
76     clear();
77     S.insert(dinic());
78     memset(vis,0,sizeof(vis));
79     find(s);
80 }
81 int p[N];
82 int main(){
83     //freopen("testdata.in","r",stdin);
84     n=read(),m=read();
85     for(int i=1;i<=m;++i){
86         int u=read(),v=read(),e=read();add(u,v,e);
87     }
88     for(int i=2;i<=n;++i) p[i]=1;
89     for(int i=2;i<=n;++i){
90         s=i,t=p[i];
91         check();
92         for(int j=i;j<=n;++j)
93         if(p[j]==t&&vis[j]) p[j]=s;
94     }
95     printf("%d\n",S.size());
96     return 0;
97 }