zoukankan      html  css  js  c++  java
  • BZOJ 2561: 最小生成树(最小割)

     

    U,V能在最小(大)生成树上,当且仅当权值比它小(大)的边无法连通U,V. 两次最小割就OK了.

    ---------------------------------------------------------------------

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
     
    #define rep(i,n) for(int i=0;i<n;++i)
    #define clr(x,c) memset(x,c,sizeof(x))
    #define Rep(i,l,r) for(int i=l;i<r;++i)
     
    using namespace std;
     
    const int inf=0x7fffffff;
    const int maxn=20002+5;
     
    struct Edge {
    int from,to,cap,flow;
    Edge(int u,int v,int c):
    from(u),to(v),cap(c),flow(0) {}
    };
     
    struct edge {
    int u,v,w;
    bool operator < (const edge &e) const {
    return w<e.w;
    }
    };
     
    vector<edge> Edges;
     
    struct ISAP {
    int n,s,t;
    int d[maxn];
    int cur[maxn];
    int num[maxn];
    int p[maxn];
    vector<int> g[maxn];
    vector<Edge> edges;
    void init(int n) {
    this->n=n;
    rep(i,n) g[i].clear();
    edges.clear();
    }
    void addEdge(int u,int v,int cap) {
    edges.push_back( Edge(u,v,cap) );
    edges.push_back( Edge(v,u,0) );
    int m=edges.size();
    g[u].push_back(m-2);
    g[v].push_back(m-1);
    }
    int augment() {
    int a=inf,x=t;
    while(x!=s) {
    Edge &e=edges[p[x]];
    a=min(e.cap-e.flow,a);
    x=e.from;
    }
    x=t;
    while(x!=s) {
    edges[p[x]].flow+=a;
    edges[p[x]^1].flow-=a;
    x=edges[p[x]].from;
    }
    return a;
    }
    int maxFlow(int s,int t) {
    this->s=s; this->t=t;
    clr(cur,0); clr(num,0);
    clr(d,0); num[0]=n;
    int flow=0,x=s;
    while(d[s]<n) {
    if(x==t) {
    flow+=augment();
    x=s;
    }
    int ok=0;
    Rep(i,cur[x],g[x].size()) {
    Edge &e=edges[g[x][i]];
    if(e.cap>e.flow && d[e.to]+1==d[x]) {
    ok=1;
    p[e.to]=g[x][i];
    cur[x]=i;
    x=e.to;
    break;
    }
    }
    if(!ok) {
    int m=n-1;
    rep(i,g[x].size()) {
    Edge &e=edges[g[x][i]];
    if(e.cap>e.flow) m=min(m,d[e.to]);
    }
    if(!--num[d[x]]) break;
    num[d[x]=m+1]++;
    cur[x]=0;
    if(x!=s) x=edges[p[x]].from;
    }
    }
    return flow;
    }
    } g;
     
    int main()
    {
    freopen("test.in","r",stdin);
    Edges.clear();
    int n,m; scanf("%d%d",&n,&m);
    int u,v,w;
    while(m--) {
    scanf("%d%d%d",&u,&v,&w);
    Edges.push_back( (edge) {u-1,v-1,w} );
    }
    sort(Edges.begin(),Edges.end());
    int U,V,L;
    scanf("%d%d%d",&U,&V,&L); --U; --V;
    g.init(n);
    rep(i,Edges.size()) {
    edge &e=Edges[i];
    if(e.w>=L) break;
    g.addEdge(e.u,e.v,1);
    g.addEdge(e.v,e.u,1);
    }
    int ans=g.maxFlow(U,V);
    g.init(n);
    for(int i=Edges.size()-1;i>=0;--i) {
    edge &e=Edges[i];
    if(e.w<=L) break;
    g.addEdge(e.u,e.v,1);
    g.addEdge(e.v,e.u,1);
    }
    ans+=g.maxFlow(U,V);
    printf("%d ",ans);
    return 0;
    }

      

    --------------------------------------------------------------------- 

    2561: 最小生成树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 727  Solved: 359
    [Submit][Status][Discuss]

    Description

     给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?

     

    Input


      第一行包含用空格隔开的两个整数,分别为N和M;
      接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
      最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
      数据保证图中没有自环。
     

    Output

     输出一行一个整数表示最少需要删掉的边的数量。

    Sample Input

    3 2
    3 2 1
    1 2 3
    1 2 2

    Sample Output

    1

    HINT

    对于20%的数据满足N ≤ 10,M ≤ 20,L ≤ 20;

      对于50%的数据满足N ≤ 300,M ≤ 3000,L ≤ 200;

      对于100%的数据满足N ≤ 20000,M ≤ 200000,L ≤ 20000。

    Source

  • 相关阅读:
    UML画图
    UML笔记
    电脑启动顺序
    评教有感
    部署图
    活动图
    给八期授课之主板电池的思考
    给八期授课之人员分配的思考
    构件图
    cocos2dx获得机器语言
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4393251.html
Copyright © 2011-2022 走看看