zoukankan      html  css  js  c++  java
  • 《洛谷P4307 [JSOI2009]球队收益 / 球队预算》

    第一眼就觉得是费用流,但是建图确实很麻烦,逐渐递增这个费用到时想到了

    solution:

    首先,对于每一个事件,我们从s向这个事件连一条容量为1的边,然后对于这个事件,向两个点连一条容量为1的边。

    这样满足了事件的关系。可以发现,我们的容量还是由s->事件的1来控制,只是有两个点的选择,即哪个点胜利。

    第二,对于每个点,我们让它向t连cnt(在事件中出现的次数)条边,每次都去增长这个费用。

    所以我们应该从最小开始,即我们一开始假定这个点在出现的事件中都输。

    假定当前赢了a局,输了b局

    那么由c*(a+1)^2+d*(b-1)^2*d - (a^2*c+b^2*d)  = (2*a+1)*c - (2*b-1)*d)

    可以发现,每多赢一次,费用都是以当前的a,b为基准来增加上面这么多费用。

    所以我们每次连边,都连容量为1,费用为较上一次增长后的费用

    那么,为什么不能连容量1,2,3,4,然后费用较原始代价增长的边呢。

    因为这样可能经过同时1,2的边,然后代价对于第一次的计算了两次,会出现不合法的更优情况,所以不行。

    // Author: levil
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 1e4;
    const int M = 1e4;
    const LL Mod = 998244353;
    #define rg register
    #define pi acos(-1)
    #define INF 1e9
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline int read(){  
            int x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
        void print(int x){
            if(x < 0){x = -x;putchar('-');}
            if(x > 9) print(x/10);
            putchar(x%10+'0');
        }
    }
    using namespace FASTIO;
    void FRE(){
        freopen("data1.in","r",stdin);
        freopen("date1.out","w",stdout);
    }
    
    int n,m,s,t,cnt = -1,maxflow = 0,mincost = 0;
    int head[N],pre[N],cal[N],dis[N],vis[N];//pre记录前驱,cal记录最短增广路上的最小流量,dis记录最短路
    struct Node{int to,dis,flow,next;}e[M<<1];
    inline void add(int u,int v,int w,int flow)//费用才是距离,流量是容量
    {
        e[++cnt].to = v,e[cnt].dis = w,e[cnt].flow = flow,e[cnt].next = head[u],head[u] = cnt;
        e[++cnt].to = u,e[cnt].dis = -w,e[cnt].flow = 0,e[cnt].next = head[v],head[v] = cnt;
    }
    bool spfa()
    {
        memset(vis,0,sizeof(vis));
        for(int i = 0;i <= t;++i) dis[i] = INF;
        queue<int> Q;
        Q.push(s);
        dis[s] = 0,vis[s] = 1,cal[s] = INF;
        while(!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            vis[u] = 0;//spfa标准操作,清除标记
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v = e[i].to,d = e[i].dis,flow = e[i].flow;
                if(flow <= 0) continue;//没有剩余流量可流
                if(dis[v] > dis[u]+d)
                {
                    dis[v] = dis[u]+d;
                    cal[v] = min(cal[u],flow);//更新增广路上的最小流量
                    pre[v] = i;//前驱记录i,因为是链式前向星
                    if(!vis[v]) vis[v] = 1,Q.push(v);
                }
            }
        }
        if(dis[t] == INF) return false;
        return true;
    }
    void MCMF()
    {
        while(spfa())
        {
            int x = t;
            maxflow += cal[t];
            mincost += dis[t]*cal[t];
            while(x!=s)
            {
                int i = pre[x];
                e[i].flow -= cal[t];
                e[i^1].flow += cal[t];
                x = e[i^1].to;
            }
        }
    }
    int A[N],B[N],C[N],D[N],sum[N];
    int main()
    {
        memset(head,-1,sizeof(head));
        n = read(),m = read();
        for(rg int i = 1;i <= n;++i) A[i] = read(),B[i] = read(),C[i] = read(),D[i] = read();
        s = 0,t = n+m+1;//t放在n,m输入下面。。
        for(rg int i = 1;i <= m;++i)
        {
            int x,y;x = read(),y = read();
            B[x]++,B[y]++;
            sum[x]++,sum[y]++;
            add(s,i,0,1);
            add(i,x+m,0,1);
            add(i,y+m,0,1);
        }
        LL ans = 0;
        for(rg int i = 1;i <= n;++i) ans += C[i]*A[i]*A[i]+D[i]*B[i]*B[i];
        for(rg int i = 1;i <= n;++i)
        {
            for(rg int j = 1;j <= sum[i];++j) 
            {
                add(i+m,t,(2*A[i]+1)*C[i]-(2*B[i]-1)*D[i],1);
                A[i]++,B[i]--;
            }
        }
        MCMF();
        printf("%lld\n",ans+mincost);
        //system("pause");     
        return 0;
    }
    View Code
  • 相关阅读:
    正则表达式
    JavaScript基础
    Servlet监听器
    Java EKT关键技术强化 tomcat中文乱码问题
    spring和springmvc 整合步骤
    [ERROR] [ERROR] Some problems were encountered while processing the POMs: [ERROR] 'packaging' with value 'war' is invalid. Aggregator projects require 'pom' as packaging. @ line 9, column 16
    Pagehelper的 使用
    异步 json的使用
    分页技术 PageHelper
    Exception encountered during context initialization
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13514433.html
Copyright © 2011-2022 走看看