您的位置:首页 > 其它

BZOJ 4519: [Cqoi2016]不同的最小割 最小割树 / 分治最小割

2017-06-28 15:52 309 查看

4519: [Cqoi2016]不同的最小割

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 763  Solved: 450

[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

Sample Output

3

和上篇blog基本一样传送门

个数用set维护一下就OK了

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();}
return x*f;
}
inline void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=900,M=20000,inf=0X3f3f3f3f;

int ecnt=1,n,a
,last
;
struct EDGE{int to,nt,val;}e[M];
inline void add(int u,int v,int val)
{e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}

int S,T,q
,d
;
bool bfs()
{
memset(d,0,sizeof(d));
int head=0,tail=1;q[0]=S,d[S]=1;
while(head<tail)
{
int u=q[head++];
for(int i=last[u];i;i=e[i].nt)
if(e[i].val&&!d[e[i].to])
{
d[e[i].to]=d[u]+1;
q[tail++]=e[i].to;
}
}
return d[T];
}

int dfs(int u,int lim)
{
if(u==T||!lim)return lim;
int res=0;
for(int tmp,i=last[u];i;i=e[i].nt)
if(d[e[i].to]==d[u]+1)
{
tmp=dfs(e[i].to,min(e[i].val,lim));
lim-=tmp;res+=tmp;e[i].val-=tmp;e[i^1].val+=tmp;
if(!lim)break;
}
if(!res)d[u]=-1;
return res;
}

void restore()
{for(int i=2;i<=ecnt;i+=2)e[i].val=e[i^1].val=(e[i].val+e[i^1].val)>>1;}

bool vis
;
void dfs(int u)
{vis[u]=1;for(int i=last[u];i;i=e[i].nt)if(!vis[e[i].to]&&e[i].val)dfs(e[i].to);}

int tmp
;
set<int> s;
void solve(int l,int r)
{
if(l==r)return ;
restore();S=a[l],T=a[r];
int mf=0;while(bfs())mf+=dfs(S,inf);
memset(vis,0,sizeof(vis));dfs(S);
s.insert(mf);int L=l,R=r;
for(int i=l;i<=r;++i)if(vis[a[i]])
tmp[L++]=a[i];else tmp[R--]=a[i];
for(int i=l;i<=r;++i)a[i]=tmp[i];
solve(l,L-1);solve(R+1,r);
}

int main()
{
n=read();int m=read();
while(m--)
{
int u=read(),v=read(),val=read();
add(u,v,val);add(v,u,val);
}
for(int i=1;i<=n;i+=3)a[i]=i,a[i+1]=i+1,a[i+2]=i+2;
solve(1,n);print(s.size());puts("");return 0;
}
/*
4 4
1 2 3
1 3 6
2 4 5
3 4 4

3
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: