bzoj2229: [Zjoi2011]最小割(最小割树)

传送门

这题是用最小割树做的(不明白最小割树是什么的可以去看看这一题->这里

有了最小割树就很简单了……点数那么少……每次跑出一个最大流就暴力搞一遍就好了

  1 //minamoto
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<queue>
  7 #define inf 0x3f3f3f3f
  8 using namespace std;
  9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 10 char buf[1<<21],*p1=buf,*p2=buf;
 11 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
 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 char sr[1<<21],z[20];int C=-1,Z;
 23 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
 24 inline void print(int x){
 25     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
 26     while(z[++Z]=x%10+48,x/=10);
 27     while(sr[++C]=z[Z],--Z);sr[++C]=‘\n‘;
 28 }
 29 const int N=205,M=10005;
 30 int head[N],Next[M],ver[M],edge[M],ee[M],tot=1;
 31 queue<int> q;
 32 inline void add(int u,int v,int e){
 33     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e,ee[tot]=e;
 34     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=e,ee[tot]=e;
 35 }
 36 int cur[N],dep[N],n,m,S,T;
 37 bool bfs(){
 38     memset(dep,-1,sizeof(dep));
 39     for(int i=1;i<=n;++i) cur[i]=head[i];
 40     while(!q.empty()) q.pop();
 41     q.push(S),dep[S]=0;
 42     while(!q.empty()){
 43         int u=q.front();q.pop();
 44         for(int i=head[u];i;i=Next[i])
 45         if(dep[ver[i]]<0&&edge[i]){
 46             q.push(ver[i]),dep[ver[i]]=dep[u]+1;
 47             if(ver[i]==T) return true;
 48         }
 49     }
 50     return false;
 51 }
 52 int dfs(int u,int limit){
 53     if(u==T||!limit) return limit;
 54     int flow=0,f;
 55     for(int i=cur[u];i;cur[u]=i=Next[i]){
 56         int v=ver[i];
 57         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
 58             flow+=f,limit-=f;
 59             edge[i]-=f,edge[i^1]+=f;
 60             if(!limit) break;
 61         }
 62     }
 63     if(!flow) dep[u]=-1;
 64     return flow;
 65 }
 66 int dinic(){
 67     int flow=0;
 68     while(bfs()) flow+=dfs(S,inf);
 69     return flow;
 70 }
 71 int id[N],tmp[N],ans[N][N];
 72 void solve(int L,int R){
 73     if(L==R) return;
 74     for(int i=2;i<=tot;i+=2) edge[i]=edge[i^1]=ee[i];
 75     S=id[L],T=id[R];
 76     int flow=dinic();
 77     for(int i=1;i<=n;++i)
 78     if(~dep[i])
 79     for(int j=1;j<=n;++j)
 80     if(dep[j]<0)
 81     cmin(ans[i][j],flow),cmin(ans[j][i],flow);
 82     int l=L,r=R;
 83     for(int i=L;i<=R;++i)
 84     if(~dep[id[i]]) tmp[l++]=id[i];
 85     else tmp[r--]=id[i];
 86     memcpy(id+L,tmp+L,sizeof(int)*(R-L+1));
 87     solve(L,l-1),solve(r+1,R);
 88 }
 89 inline void init(){
 90     memset(head,0,sizeof(head)),tot=1,memset(ans,0x3f,sizeof(ans));
 91 }
 92 int main(){
 93     //freopen("testdata.in","r",stdin);
 94     int T=read();
 95     while(T--){
 96         init();
 97         n=read(),m=read();
 98         for(int i=1;i<=m;++i){
 99             int u=read(),v=read(),e=read();add(u,v,e);
100         }
101         for(int i=1;i<=n;++i) id[i]=i;
102         solve(1,n);
103         int q=read();
104         while(q--){
105             int k=read(),res=0;
106             for(int i=1;i<=n;++i)
107             for(int j=i+1;j<=n;++j)
108             if(ans[i][j]<=k) ++res;
109             print(res);
110         }
111         sr[++C]=‘\n‘;
112     }
113     Ot();
114     return 0;
115 }

原文地址:https://www.cnblogs.com/bztMinamoto/p/9571271.html

时间: 2024-11-08 12:03:54

bzoj2229: [Zjoi2011]最小割(最小割树)的相关文章

[bzoj2229][Zjoi2011]最小割_网络流_最小割树

最小割 bzoj-2229 Zjoi-2011 题目大意:题目链接. 注释:略. 想法: 在这里给出最小割树的定义. 最小割树啊,就是这样一棵树.一个图的最小割树满足这棵树上任意两点之间的最小值就是原图中这两点之间的最小割. 这个性质显然是非常优秀的. 我们不妨这样假设,我么已经把最小割树求出来了,那么这个题就迎刃而解了. 我们可以直接枚举点对,然后暴力验证就可以直接枚举出所有的合法点对是吧. 那么问题来了,我们如何才能求出所有的合法的点对? 这就需要用到了最小割树的构建过程. 我们最小割树的构

bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)

2229: [Zjoi2011]最小割 题目:传送门 题解: 一道非常好的题目啊!!! 蒟蒻的想法:暴力枚举点对跑最小割记录...绝对爆炸啊.... 开始怀疑是不是题目骗人...难道根本不用网络流???一看路牌....分治最小割?最小割树? 然后开始各种%论文... 简单来说吧,根据各种本蒟蒻不会证明的理论,那么:所有最小割都不是完全独立的,总共有n-1种(也就是树上的n-1条边)最小割 恰好和树的定义一样啊! 那么用一个solve递归函数来解决,一开始任意找两个点作为st和ed来最小割,然后分

scu - 3254 - Rain and Fgj(最小点权割)

题意:N个点.M条边(2 <= N <= 1000 , 0 <= M <= 10^5),每一个点有个权值W(0 <= W <= 10^5),现要去除一些点(不能去掉点0),使得结点 0 与结点 N - 1 不连通,求去掉的点的最小权值和. 题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=3254 -->>这是很明显的最小点权割.. 建图方案: 1)将全部点 i 拆成 i 和 i + N.i ->

3532: [Sdoi2014]Lis 最小字典序最小割

3532: [Sdoi2014]Lis Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 865  Solved: 311[Submit][Status][Discuss] Description 给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci.请删除若干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案.如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种. 这题难点在如何求一组最小字典序最小的最小

关于最小代价子母树

第一次尝试写动态规划(Dynamic Planning)= 问题如下: ------------------------------------------------------------------------------------------------------------------------- 最小代价子母树 设有一排数,共n个,例如:22 14 7 13 26 15 11.任意2个相邻的数可以进行归并,归并的代价为该两个数的和,经过不断的归并,最后归为一堆,而全部归并代价的

poj 3522 Slim Span 最大边减最小边最小的生成树

枚举最小边进行kruskal. #include <cstdio> #include <algorithm> using namespace std; #define maxn 120 #define maxm 10000 struct edge { int u,v,w; }e[maxm]; int p[maxn],n,m; int find(int x) { if(x==p[x]) return x; return p[x]=find(p[x]); } void link(int

【BZOJ-2229】最小割 最小割树(最大流+分治)

2229: [Zjoi2011]最小割 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1565  Solved: 560[Submit][Status][Discuss] Description 小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割. 对于带权图来说,将所有顶点处在不同部分的边的

[BZOJ2229][ZJOI2011]最小割

bzoj luogu sol 最小割树请转一道很相似完全一模一样的题 所以跑出所有点对之间的最小割然后暴力统计答案即可. code #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; int gi() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&a

[ZJOI2011] 最小割 - 最小割树

最小割树裸题 建树后,以每个点为根跑DFS求出距离矩阵,然后暴力回答询问即可 #include <bits/stdc++.h> using namespace std; #define int long long const int maxn=6e2; const int maxm=4e4; const int inf=1e13; int n,m,q; //for the target graph vector <pair<int,int> > g[maxn]; voi