• HDU3315 费用流


    为了不让颓影响到学习= = (主要是颓得不想敲代码)

    所以,决定在OJ上随便挑一题,能搞便搞,不会就找题解,扒过来,认真研究。。。。。。(比如这题

    原帖:http://m.blog.csdn.net/blog/u013480600/39185029

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3315

    题目还是看得懂的。。。。

    输入分两部分,第一部分;最初的决策

    回合数   每回合分数   S在每回合的血量   X在每回合的血量   S在每回合的攻击力   X在每回合的攻击力

    第二部分  :更改后的决策:(内容相同)

    现在要你重新安排S和X的决斗顺序,使得你能获得的分最多.如果有多个最优解,你要选取那个维持初始决斗顺序最多的解

    求 S能得到的最大分数,两个决策的相似度(没懂)   如果不可能改决策后赢比赛,再输出“Oh, I lose my dear seaco!”





    关键就是那个相似度的东西- - 表示不懂- - ~

    原帖分析:

    本题之前用的二分图最优匹配做的:

    http://blog.csdn.net/u013480600/article/details/38737449

           这里用费用流再做一遍,首先我们求出任意Si与Xj决斗时,你能获得的分值Wij. 下面网络流建图:

           源点s编号0, S1到Sn编号1到n, X1到Xn编号n+1到2*n, 汇点t编号2*n+1.

           源点s到任意Si点有边 (s, i, 1, 0)

           任意Xi点到汇点t有边 (i+n, t, 1, 0)

           如果Si与Xj决斗的解过为Wij分值,那么有下面两种情况:

           i==j时, 有边(i ,j+n, 1, -Wij*(n+1)-1) (注意这里Wij取负数且乘以(n+1)且减一,取负数,是因为最终结果取反是你能获得的最大分数.减一是使得该原始决斗顺序能够得以保留.乘以(n+1)是因为把权值扩大n+1倍之后再+1最终的权值就算是+n然后除以(n+1)还是能得到正真的分数值 )

           i!=j时,有边(i,j+n,1,-Wij*(n+1) )

           最终我们求最小费用的负数X即可. X%(n+1)就是我们保持原先决斗顺序的个数,X/(n+1)就是我们能获得的最终分数.

    AC代码: G++提交

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #define INF 1e9
    using namespace std;
    const int maxn=200+5;//这里写180+5就出错,题目n的范围应该<=100
    
    struct Edge
    {
        int from,to,cap,flow,cost;
        Edge(){}
        Edge(int f,int t,int c,int fl,int co):from(f),to(t),cap(c),flow(fl),cost(co){}
    };
    
    struct MCMF
    {
        int n,m,s,t;
        vector<Edge> edges;
        vector<int> G[maxn];
        bool inq[maxn];
        int p[maxn];
        int d[maxn];
        int a[maxn];
    
        void init(int n,int s,int t)
        {
            this->n=n, this->s=s, this->t=t;
            edges.clear();
            for(int i=0;i<n;++i) G[i].clear();
        }
    
        void AddEdge(int from,int to,int cap,int cost)
        {
            edges.push_back(Edge(from,to,cap,0,cost));
            edges.push_back(Edge(to,from,0,0,-cost));
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool BellmanFord(int &flow,int &cost)
        {
            queue<int> Q;
            for(int i=0;i<n;++i) d[i]=INF;
            memset(inq,0,sizeof(inq));
            Q.push(s),inq[s]=true,d[s]=0,a[s]=INF,p[s]=0;
    
            while(!Q.empty())
            {
                int u=Q.front(); Q.pop();
                inq[u]=false;
                for(int i=0;i<G[u].size();++i)
                {
                    Edge &e=edges[G[u][i]];
                    if(e.cap>e.flow && d[e.to]>d[u]+e.cost)
                    {
                        d[e.to]=d[u]+e.cost;
                        a[e.to]=min(a[u],e.cap-e.flow);
                        p[e.to]=G[u][i];
                        if(!inq[e.to]){inq[e.to]=true; Q.push(e.to);}
                    }
                }
            }
            if(d[t]==INF) return false;
            flow += a[t];
            cost += d[t]*a[t];
            int u=t;
            while(u!=s)
            {
                edges[p[u]].flow +=a[t];
                edges[p[u]^1].flow -=a[t];
                u=edges[p[u]].from;
            }
            return true;
        }
    
        int solve()
        {
            int flow=0,cost=0;
            while(BellmanFord(flow,cost));
            return cost;
        }
    }MM;
    
    int n;
    int v[maxn],h[maxn],p[maxn],a[maxn],b[maxn];
    int ack(int i,int j)//返回Si与Xj决斗的结果分数
    {
        int sum1=h[i],sum2=p[j];
        while(true)
        {
            sum2 -= a[i];
            if(sum2<=0) return v[i];
            sum1 -= b[j];
            if(sum1<=0) return -v[i];
        }
    }
    
    int main()
    {
        while(scanf("%d",&n)==1 && n)
        {
            for(int i=1;i<=n;++i) scanf("%d",&v[i]);
            for(int i=1;i<=n;++i) scanf("%d",&h[i]);
            for(int i=1;i<=n;++i) scanf("%d",&p[i]);
            for(int i=1;i<=n;++i) scanf("%d",&a[i]);
            for(int i=1;i<=n;++i) scanf("%d",&b[i]);
    
            int src=0,dst=2*n+1;
            MM.init(2*n+2,src,dst);
            for(int i=1;i<=n;++i)
            {
                MM.AddEdge(src,i,1,0);
                MM.AddEdge(i+n,dst,1,0);
            }
    
            for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
            {
                int score = -ack(i,j)*(n+1);
                if(i==j) --score;
                MM.AddEdge(i,j+n,1,score);
            }
    
            int ans = -MM.solve();
    
            int v1=ans/(n+1);//最大分数
            int v2=ans%(n+1);//用到的老边数
            if(v1<=0) printf("Oh, I lose my dear seaco!
    ");
            else printf("%d %.3lf%%
    ",v1,100.0*v2/n);
        }
        return 0;
    }



  • 相关阅读:
    函数递归,匿名函数
    生成器
    迭代器
    有参函数(认证功能)
    闭包函数和装饰器
    文件处理
    Celery介绍
    Redis 介绍
    GIT知识点
    前后端分离-前端配置
  • 原文地址:https://www.cnblogs.com/XqwKen/p/4564316.html
Copyright © 2020-2023  润新知