zoukankan      html  css  js  c++  java
  • [最小割树] Luogu P4897 最小割树

    题目描述

    给定一个nn个点mm条边的无向连通图,多次询问两点之间的最小割

    两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不连通

    输入输出格式

    输入格式:

    第一行两个数n,mn,m

    接下来mm行,每行33个数u,v,wu,v,w,表示有一条连接uu与vv的无向边,割断它的代价为ww

    接下来这一行有一个整数QQ,表示询问次数

    接下来QQ行,每行两个数u,vu,v,你需要求出uu与vv之间的最小割

    注意:因为数据有误,给定图的真实点数应该是n+1n+1个,编号为00到nn

    输出格式:

    输出共QQ行,每行一个整数对应询问的答案

    输入输出样例

    输入样例#1:
    4 5
    1 2 2
    2 3 2
    4 2 3
    4 3 1
    1 3 1
    3
    1 4
    2 4
    2 3
    输出样例#1:
    3
    4
    4

    说明

    nleq 500,quad mleq 1500,quad Qleq 10^5,quad 0leq wleq 10^4n500,m1500,Q105,0w104

    题解

    • 一开始把所有点放进一个集合里面

    • 先从集合中随意取出两个点作为源汇,在整个图中跑一遍最大流,就得到了这两个点的最小割

    • 并把所有点分为了s集和t集,那么就更新s集到t集的答案,并把s集和t集往下递归

    • 以此类推,到最后即可得到所有点对的最小割

    代码

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <queue>
     6 #define inf 0x3f3f3f3f
     7 #define N 510
     8 using namespace std;
     9 int s,t,cnt=1,n,m,q,dis[N],head[N],a[N],tmp[N],ans[N][N],mark[N];
    10 struct edge{int to,c,from;}e[N*200];
    11 queue <int> Q;
    12 void insert(int u,int v,int c)
    13 {
    14     e[++cnt].to=v,e[cnt].c=c,e[cnt].from=head[u],head[u]=cnt;
    15     e[++cnt].to=u,e[cnt].c=c,e[cnt].from=head[v],head[v]=cnt;
    16 }
    17 bool bfs()
    18 {
    19     memset(dis,0,sizeof(dis)),dis[s]=2;
    20     while (!Q.empty()) Q.pop(); Q.push(s);
    21     while (!Q.empty())
    22     {
    23         int u=Q.front(); Q.pop();
    24         for (int i=head[u];i;i=e[i].from)
    25             if (e[i].c&&!dis[e[i].to])
    26             {
    27                 dis[e[i].to]=dis[u]+1;
    28                 if (e[i].to==t) return 1;
    29                 Q.push(e[i].to);
    30             }
    31     }
    32     return 0;
    33 }
    34 int dfs(int x,int maxf)
    35 {
    36     if (x==t||!maxf) return maxf;
    37     int ret=0;
    38     for (int i=head[x];i;i=e[i].from)
    39         if (e[i].c&&dis[e[i].to]==dis[x]+1)
    40         {
    41             int f=dfs(e[i].to,min(e[i].c,maxf-ret));
    42             e[i].c-=f,e[i^1].c+=f,ret+=f;
    43             if (ret==maxf) break;
    44         }
    45     if (!ret) dis[x]=0;
    46     return ret;
    47 }
    48 void dfs(int x)
    49 {
    50     mark[x]=1;
    51     for (int i=head[x];i;i=e[i].from) if (e[i].c&&!mark[e[i].to]) dfs(e[i].to);
    52 }
    53 void solve(int l,int r)
    54 {
    55     if (l==r) return;
    56     s=a[l],t=a[r];
    57     for (int i=2;i<=cnt;i+=2) e[i].c=e[i^1].c=(e[i].c+e[i^1].c)/2;
    58     int flow=0;
    59     while (bfs()) flow+=dfs(s,inf);
    60     memset(mark,0,sizeof(mark)),dfs(s);
    61     for (int i=1;i<=n;i++) if (mark[i]) for (int j=1;j<=n;j++) if (!mark[j]) ans[i][j]=ans[j][i]=min(ans[i][j],flow);
    62     int i=l,j=r;
    63     for (int k=l;k<=r;k++) if (mark[a[k]]) tmp[i++]=a[k]; else tmp[j--]=a[k];
    64     for (int k=l;k<=r;k++) a[k]=tmp[k];
    65     solve(l,i-1),solve(j+1,r);
    66 }
    67 int main()
    68 {
    69     scanf("%d%d",&n,&m);    
    70     for (int i=1;i<=n;i++) a[i]=i;
    71     memset(ans,inf,sizeof(ans));
    72     for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z);
    73     solve(1,n),scanf("%d",&q);
    74     for (int i=1,x,y;i<=q;i++) scanf("%d%d",&x,&y),printf("%d
    ",ans[x][y]); 
    75 }

     

  • 相关阅读:
    repeater 相关问题
    发布网站的步骤
    HTTP 错误 500.19- Internal Server Error 错误解决方法
    没有body怎么添加onload事件
    js 一搬问题汇总
    取值为四舍五入方法实现
    有关网站中操作数据库的几种方法的使用情况
    正式开始使用window live write 来更新使用博客园
    设置Oracle PL/SQL 时间显示格式 NLS_TIMESTAMP_FORMAT 2008-01-27 00:04:35:877000
    JSP 显示服务器上的文件/图片
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11220179.html
Copyright © 2011-2022 走看看