题目描述
小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: ”对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。
对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割“
现给定一张无向图,小白有若干个形如”图中有多少对点它们的最小割的容量不超过x呢“的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。
输入输出格式
输入格式:
输入文件第一行有且只有一个正整数T,表示测试数据的组数。 对于每组测试数据, 第一行包含两个整数n,m,表示图的点数和边数。下面m行,每行3个正整数u,v,c(1<=u,v<=n,0<=c<=106),表示有一条权为c的无向边(u,v) 接下来一行,包含一个整数q,表示询问的个数 下面q行,每行一个整数x,其含义同题目描述。
输出格式:
对于每组测试数据,输出应包括q行,第i行表示第i个问题的答案。对于点对(p,q)和(q,p),只统计一次(见样例)。两组测试数据之间用空行隔开。
分析:
1.貌似这类要求的东西很多的题目都往分治方面去想。
2.设S1-T1的割集为C1,S2-T2的割集为C2,则,C1和C2必定不是跨立的(一定为包含关系或没有交集)。那么一共就只有n-1个本质不同的割。
3.所以我们的具体做法是分治处理——先任意取S和T做网络流,那么原图就分成了与S相连的部分S’和与T相连的部分T’,此时分别在S’T’中的点对的最小割就是S和T的最小割。再递归并更新答案即可。
4.注意在每次网络流之前一定要把网络还原为初始网络。
#include
#include
#include
#include
#include
using namespace std;
const int maxn=160;
const int maxm=6100;
const int INF=1e9;
int to[maxm],Next[maxm],Begin[maxn],w[maxm],e;
int dis[maxn],gap[maxn],d[maxn];
int n,m;
int S,T,tot;
void add(int x,int y,int z){
to[++e]=y;
Next[e]=Begin[x];
Begin[x]=e;
w[e]=z;
}
bool bfs(){
memset(dis,0,sizeof(dis));
queue<int>q;
q.push(S);dis[S]=1;
int v;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=Begin[u];i;i=Next[i])if(w[i]>0 && (!dis[v=to[i]])){
dis[v]=dis[u]+1;
q.push(v);
}
}
return dis[T];
}
int cur[maxn];
int dfs(int x,int flow){
if(x==T) return flow;
int v,tmp,ret=0;
for(int &i=cur[x];i;i=Next[i]){if(w[i]>0 && dis[v=to[i]]==dis[x]+1)
if((tmp=dfs(v,min(flow,w[i])))){
w[i]-=tmp;w[i^1]+=tmp;
flow-=tmp;ret+=tmp;
}
if(!flow) return ret;
}
return ret;
}
int cut[maxn][maxn];
int Maxflow(int s,int t){
S=s,T=t;
int maxflow=0;
while(bfs()){
for(int i=1;i<=n;i++) cur[i]=Begin[i];
maxflow+=dfs(S,INF);
}
return maxflow;
}
int id[maxn],tmp[maxn];
int w1[maxm];
void solve(int L,int R){
if(L==R) return;
for(int i=2;i<=e;i++) w[i]=w1[i];
int ret=Maxflow(id[L],id[R]),l=L,r=R;
for(int i=1;i<=n;i++)if(dis[i]){
for(int j=1;j<=n;j++)if(!dis[j]) cut[i][j]=cut[j][i]=min(cut[i][j],ret);
}
for(int i=L;i<=R;i++) tmp[dis[id[i]]?l++:r--]=id[i];
for(int i=L;i<=R;i++) id[i]=tmp[i];
solve(L,r);solve(l,R);
}
int main(){
int kase;
scanf("%d",&kase);
while(kase--){
e=1;
scanf("%d%d",&n,&m);
memset(Begin,0,sizeof(Begin));
for(int i=1;i<=n;i++) id[i]=i;
for(int i=1;i<=m;i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);add(v,u,c);
}
for(int i=2;i<=e;i++) w1[i]=w[i];
memset(cut,0x7f,sizeof(cut));
solve(1,n);
int q;
scanf("%d",&q);
while(q--){
int p,ans=0;
scanf("%d",&p);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(cut[i][j]<=p) ans++;
printf("%d\n",ans);
}
if(kase) puts("");
}
return 0;
}
^_^