HDU3315 費用流

爲了避免讓頹影響到學習= = (主要是頹得不想敲代碼)
php

因此,決定在OJ上隨便挑一題,能搞便搞,不會就找題解,扒過來,認真研究。。。。。。(好比這題網絡

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

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

題目仍是看得懂的。。。。spa

輸入分兩部分,第一部分;最初的決策.net

回合數\n   每回合分數\n   S在每回合的血量\n  X在每回合的血量\n  S在每回合的攻擊力\n  X在每回合的攻擊力\ncode

第二部分  :更改後的決策:(內容相同)blog

如今要你從新安排S和X的決鬥順序,使得你能得到的分最多.若是有多個最優解,你要選取那個維持初始決鬥順序最多的解
get

求 S能獲得的最大分數,兩個決策的類似度(沒懂)   若是不可能改決策後贏比賽,再輸出「Oh, I lose my dear seaco!」string





關鍵就是那個類似度的東西- - 表示不懂- - ~

原帖分析:

本題以前用的二分圖最優匹配作的:

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!\n");
        else printf("%d %.3lf%%\n",v1,100.0*v2/n);
    }
    return 0;
}
相關文章
相關標籤/搜索