4519: [Cqoi2016]不同的最小割
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 593 Solved: 362
[Submit][Status][Discuss]
Description
学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成
两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。对于带权图来说,将
所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在
关于s,t的割中容量最小的割。
而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了。我们可以把
视野放宽,考虑有N个点的无向连通图中所有点对的最小割的容量,共能得到N(N−1)
2个数值。
这些数值中互不相同的有多少个呢?这似乎是个有趣的问题。
Input
输入文件第一行包含两个数N,M,表示点数和边数。接下来M行,每行三个数u,v,w,
表示点u和点v(从1开始标号)之间有条边权值是w。
1<=N<=850 1<=M<=8500 1<=W<=100000
Output
输出文件第一行为一个整数,表示个数。
Sample Input
4 4
1 2 3
1 3 6
2 4 5
3 4 4
1 2 3
1 3 6
2 4 5
3 4 4
Sample Output
3
HINT
Source
---------------------------------------
分治最小割/最小割树 刚学的新姿势
只会写板子并不会证明
分治点集 每次在当前点集内随意选两个点跑最小割
把当前点集分成两个分治下去
最终答案只有 n-1种
说了半天也说不明白。。。
代码:
#include<cmath> #include<vector> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define For(i,x,y) for(int i=x;i<=y;++i) using namespace std; const int N = 8505; const int inf = 1e9; int n,m; int x[N],y[N],_c[N]; int map[N][N]; int p[N]; vector<int>V; struct Graph{ int head[N],nxt[N*2],to[N*2],c[N*2],cnt; int dis[N];int q[N*100];int vis[N];int Clo; bool mark[N];bool In[N]; int s,t; void add(int u,int v,int C){ nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;c[cnt]=C; nxt[++cnt]=head[v];head[v]=cnt;to[cnt]=u;c[cnt]=C; } void init(int l,int r){ memset(mark,0,sizeof(mark)); for(int i=2;i<=cnt;i+=2) c[i]=c[i^1]=c[i]+c[i^1]>>1; s=p[l];t=p[r]; } bool bfs(){ For(i,1,n) dis[i] = inf; dis[s]=0; int l=0,r=0; q[0]=s; while(l<=r){ int u=q[l++]; for(int i=head[u];i;i=nxt[i]){ int v=to[i];if(!c[i]) continue; if(dis[v]>dis[u]+1){ dis[v]=dis[u]+1; q[++r]=v; } } } return dis[t]<1e9; } int dfs(int u,int mf){ if(u==t) return mf; int flow=0,tf; vis[u]=Clo; for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(vis[v]!=Clo&&dis[v]==dis[u]+1&&c[i]&&mf&&(tf=dfs(v,min(mf,c[i])))){ flow+=tf;mf-=tf;c[i]-=tf;c[i^1]+=tf; } } return flow; } int Maxflow(){ int flow=0,tf; while(bfs()){ Clo++; while((tf=dfs(s,inf))){ Clo++;flow+=tf; } } return flow; } void Dfs(int u,int fat){ mark[u]=1; for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(mark[v]||c[i]==0) continue; Dfs(v,u); } } }G; int res; int tmp[N]; void solve(int l,int r){ if(l==r) return; G.init(l,r); int Ta=G.Maxflow(); V.push_back(Ta); G.Dfs(p[l],p[l]); int i=l-1,j=r+1; for(int P=l;P<=r;++P){ if(G.mark[p[P]]) tmp[++i]=p[P]; else tmp[--j]=p[P]; } For(i,l,r) p[i]=tmp[i]; solve(l,i);solve(j,r); } int main(){ scanf("%d%d",&n,&m); For(i,1,m) scanf("%d%d%d",&x[i],&y[i],&_c[i]); G.cnt=1;For(i,1,m) G.add(x[i],y[i],_c[i]); For(i,1,n) p[i]=i; solve(1,n); sort(V.begin(),V.end()); int F=0;V.push_back(-100); for(int i=0;i<V.size()-1;++i){ if(V[i]!=V[i+1]){ F++; } } printf("%d",F); return 0; }