zoukankan      html  css  js  c++  java
  • [费用流] HDU 6767 New Equipments

    2020 Multi-University Training Contest 2 (1005)

    题目大意

    懒得翻译了

    Hall 定理

    设二部图(G=langle V_1,V_2,E angle)中,(|V_1|leq|V_2|). (G) 中存在从 (V_1)(V_2) 的完备匹配当且仅当 (V_1) 中任意 (k) 个顶点至少与 (V_2) 中的 (k) 个顶点相邻 ((k=1,2,dots,|V_1|)).

    设二部图 (G=langle V_1,V_2,E angle) 中, 如果存在 (tgeq 1), 使得 (V_1) 中每个顶点至少关联 (t) 条边, 而 (V_2) 中每个顶点至多关联 (t) 条边,则 (G) 中存在 (V_1)(V_2) 的完备匹配。

    题解

    对于这道题,因为最多只有50个开口向上的二次函数,我们可以在每个二次函数的对称轴附近选取50个点,然后每个代表二次函数的点向每个代表 (x) 值的点连边,边权是二次函数在 (x) 处对应的函数值。由 Hall 定理可知,该二分图一定存在完备匹配。建完图后直接跑一遍费用流求出最小费用即可。

    这道题比赛时想到了正解没写出来,太可惜了。一是没有开long long,二是他要求匹配数分别为 (1sim n) 的最小代价。注意到每次找到的增广路增广的流量至多为1,只要每增广一次,记录一下答案即可,而不用跑 (n) 次费用流。

    Code

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <vector>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    const LL INF=1LL<<60;
    struct edge{int next,to,c;LL w;};
    edge G[1000010];
    int head[3010];
    LL Dis[3010];
    int Pre[3010];
    int incf[3010];
    bool inQ[3010];
    LL a[60],b[60],c[60];
    int N,M,S,T,cnt=2,MaxFlow=0;
    LL MinCost=0;
    
    template<typename elemType>
    inline void Read(elemType &T){
        elemType X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        T=(w?-X:X);
    }
    
    inline void add_edge(int u,int v,int c,LL w){
        G[cnt].c=c;
        G[cnt].w=w;
        G[cnt].to=v;
        G[cnt].next=head[u];
        head[u]=cnt++;
        return;
    }
    
    bool SPFA(){
        queue<int> Q;
        memset(Dis,0x3f,sizeof(Dis));    
        memset(inQ,0,sizeof(inQ));
        Q.push(S);Dis[S]=0;incf[S]=1<<29;inQ[S]=true;
        while(!Q.empty()){
            int now=Q.front();Q.pop();inQ[now]=false;
            for(int i=head[now];i;i=G[i].next){
                if(!G[i].c) continue;
                if(Dis[G[i].to]>Dis[now]+G[i].w){
                    Dis[G[i].to]=Dis[now]+G[i].w;
                    incf[G[i].to]=min(incf[now],G[i].c);
                    Pre[G[i].to]=i;
                    if(!inQ[G[i].to]){
                        Q.push(G[i].to);
                        inQ[G[i].to]=true;
                    }
                }
            }
        }
        if(Dis[T]>INF) return false;
        return true;
    }
    
    inline void Update(){
        int u=T;
        while(u!=S){
            int i=Pre[u];
            G[i].c-=incf[T];
            G[i^1].c+=incf[T];
            u=G[i^1].to;
        }
        MaxFlow+=incf[T];
        MinCost+=Dis[T]*incf[T];
        return;
    }
    
    vector<int> Range;
    int Ans[100];
    int Test;
    
    int main(){
        Read(Test);
        while(Test--){
            int n,m;
            Read(n);Read(m);
            for(RG i=1;i<=n;++i){
                Read(a[i]);
                Read(b[i]);
                Read(c[i]);
            }
            Range.clear();
            for(RG i=1;i<=n;++i){
                int center=-b[i]/(a[i]<<1);
                int Len=n/2+2;
                if(center-Len+1<1){
                    for(RG j=1;j<=min(m,Len*2);++j)
                        Range.push_back(j);
                }else if(center+Len-1>m){
                    for(RG j=max(1,m-Len*2);j<=m;++j)
                        Range.push_back(j);
                }else{
                    for(RG j=max(1,center-Len+1);j<=min(m,center+Len-1);++j)
                        Range.push_back(j);
                }
            }
            sort(Range.begin(),Range.end());
            Range.erase(unique(Range.begin(),Range.end()),Range.end());
            int Num=Range.size();
            cnt=2;
            memset(head,0,sizeof(head));
            MaxFlow=MinCost=0;
            for(RG i=0;i<Num;++i){
                LL x=Range[i];
                for(RG j=1;j<=n;++j){
                    LL w=a[j]*x*x+b[j]*x+c[j];
                    add_edge(Num+j,i+1,1,w);
                    add_edge(i+1,Num+j,0,-w);
                }
            }
            N=Num+n+3;
            int SS=Num+n+1;
            T=Num+n+2;S=Num+n+3;
            for(RG i=1;i<=n;++i){
                add_edge(SS,Num+i,1,0);
                add_edge(Num+i,SS,0,0);
            }
            for(RG i=1;i<=Num;++i){
                add_edge(i,T,1,0);
                add_edge(T,i,0,0);
            }
            add_edge(SS,S,0,0);
            add_edge(S,SS,n,0);
            
            for(RG k=1;k<=n;++k){
                if(SPFA()) Update();
                printf("%lld",MinCost);
                if(k<n) printf(" ");
            }
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    个人技术博客(α)
    git常用命令合集
    软件工程实践2017第二次结对作业
    软件工程实践2017第一次结对作业
    软件工程实践2017第二次作业
    软件工程实践2017第一次作业
    学习总结
    约瑟夫
    今天是星期几
    斐波那契数列取石子游戏
  • 原文地址:https://www.cnblogs.com/AEMShana/p/13370214.html
Copyright © 2011-2022 走看看