bzoj 2229: [Zjoi2011]最小割

Description

小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。 对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割” 现给定一张无向图,小白有若干个形如“图中有多少对点它们的最小割的容量不超过x呢”的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。

Input

输入文件第一行有且只有一个正整数T,表示测试数据的组数。 对于每组测试数据, 第一行包含两个整数n,m,表示图的点数和边数。 下面m行,每行3个正整数u,v,c(1<=u,v<=n,0<=c<=106),表示有一条权为c的无向边(u,v) 接下来一行,包含一个整数q,表示询问的个数 下面q行,每行一个整数x,其含义同题目描述。

Output

对于每组测试数据,输出应包括q行,第i行表示第i个问题的答案。对于点对(p,q)和(q,p),只统计一次(见样例)。

两组测试数据之间用空行隔开。

Sample Input

1
5 0
1
0

Sample Output

10

【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。

图中两个点之间可能有多条边


分治求最小割

s到t最小割为s.则s在残余网络可以到的点集和t可以到的最小割可能为当前最小割。

然后分两块分治做取min即可求出两两间最小割

最后n^2暴力统计即可

#include
#include
#include
#include
#include
using namespace std;
int map[201][201];
struct line
{
     int s,t;
     int f;
     int la;
     bool flag;
     int next;
}a[6001];
int head[201];
int edge;
inline void add(int s,int t,int f)
{
	 a[edge].next=head[s];
	 head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
     a[edge].f=f;
     a[edge].la=f;
     a[edge].flag=true;
}
queue Q;
int dep[201];
inline bool bfs(int ss,int tt)
{
	 memset(dep,-1,sizeof(dep));
	 Q.push(ss);
	 dep[ss]=0;
	 int i;
	 while(!Q.empty())
	 {
	      int d=Q.front();
	      Q.pop();
	      for(i=head[d];i!=0;i=a[i].next)
	      {
	           int t=a[i].t;
	           if(a[i].f>0&&dep[t]==-1) 
	           {
	                dep[t]=dep[d]+1;
	                Q.push(t);
	           }
	      }
	 }
     if(dep[tt]==-1)
          return false;
     return true;
}
inline int dfs(int d,int s,int tt)
{
     if(d==tt)
          return s;
     int i;
     int ts=s;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
		  if(dep[t]==dep[d]+1&&a[i].f>0)
		  {
		       int x=dfs(t,min(s,a[i].f),tt);
		       s-=x;
		       a[i].f-=x;
		       if(i%2==1)
		            a[i+1].f+=x;
		       else
		            a[i-1].f+=x;
		  }
	 }
	 if(ts==s)
	      dep[d]=-1;
	 return ts-s;
}
inline int dinic(int s,int t)
{
	 int ans=0;
     while(bfs(s,t))
          ans+=dfs(s,2100000000,t);
     return ans;
}
int sx[3001],tx[3001],xx[3001];
int n;
/*int v[1001];
inline void bfsx(int s,int xx)
{
     Q.push(s);
     v[s]=xx;
     int i;
     while(!Q.empty())
     {
          int d=Q.front();
          Q.pop();
          for(i=head[d];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               int xt;
               if(i%2==0)
                    xt=a[i-1].f;
               else
                    xt=a[i+1].f;
               if(v[t]==0&&a[i].f>0&&a[i].flag)
               {
                    v[t]=1;
                    Q.push(t);
               }
          }
     }
}*/
bool vx[1001];
inline void bfsx2(int s,int xx)
{
	 memset(vx,false,sizeof(vx));
     Q.push(s);
  //   v[s]=xx;
     vx[s]=true;
     int i;
     while(!Q.empty())
     {
          int d=Q.front();
          Q.pop();
          for(i=head[d];i!=0;i=a[i].next)
          {
               int t=a[i].t;
               if(a[i].f>0/*&&xt>0*/&&!vx[t])
               {
               	    vx[t]=true;
               	   // if(v[t]==1)
                    //     v[t]=2;
                    Q.push(t);
               }
          }
     }
}
int b[1001],c[1001];
inline void solve(int s,int t)
{
	 if(s>=t)
	      return ;
   //  memset(v,0,sizeof(v));
//	 bfsx(s,1);
     int xt=dinic(b[s],b[t]);
     bfsx2(b[s],2);
     int i,j;
     for(i=1;i<=n;i++)
     {
     	/*  if(v[i]==2&&i!=s)
     	       s1=i;
     	  else if(v[i]==1&&i!=t)
     	       s2=i;*/
     	  if(!vx[i])
     	       continue;
     	  for(j=1;j<=n;j++)
     	  {
     	  	   if(vx[j]||i==j)
     	  	        continue;
     	  	  // {
                    map[i][j]=min(map[i][j],xt);
                    map[j][i]=min(map[j][i],xt);
               //}
          }
     }
     int p=0;
     for(i=s;i<=t;i++)
     {
          if(vx[b[i]])
          {
               p++;
               c[p]=b[i];
          }
     }
     int pp=p+s-1;
     for(i=s;i<=t;i++)
     {
          if(!vx[b[i]])
          {
               p++;
               c[p]=b[i];
          }
     }
     int p1=0;
     for(i=s;i<=t;i++)
     {
     	  p1++;
          b[i]=c[p1];
     }
     for(i=1;i<=edge;i++)
          a[i].f=a[i].la;
  //   if(xt!=0)
    // {
          solve(s,pp);
          solve(pp+1,t);
     //}
}
int px[1001];
int main()
{
     int T;
	 scanf("%d",&T);
	 while(T>0)
	 {
	 T--;
     int m;
     scanf("%d%d",&n,&m);
     int i,j,k;
     memset(head,0,sizeof(head));
     edge=0;
     for(i=1;i<=m;i++)
     {
          scanf("%d%d%d",&sx[i],&tx[i],&xx[i]);
          edge++;
          add(sx[i],tx[i],xx[i]);
          edge++;
          add(tx[i],sx[i],xx[i]);
     }
     memset(map,127/3,sizeof(map));
     for(i=1;i<=n;i++)
          map[i][i]=0;
     for(i=1;i<=n;i++)
          b[i]=i;
     solve(1,n);
     int q;
     scanf("%d",&q);
     int x;
     for(k=1;k<=q;k++)
     {
     scanf("%d",&x);
     int ans=0;
     for(i=1;i<=n;i++)
     {
          for(j=i+1;j<=n;j++)
          {
               if(map[i][j]==map[0][0]||map[i][j]<=x)
                    ans++;
          }
     }
     printf("%d\n",ans);
     }
     if(k!=q)
          printf("\n");
     }
     return 0;
}


你可能感兴趣的:(最小割,分治)