BZOJ 1449:[JSOI2009]チームは、最小コストの最大フローを返します

タイトル

\(〜\)
BZOJ 1449
LUOGU 4307
説明

バスケットボールリーグでは、そこ(N \)\チーム、支出のチームは、スクリーニングの結果であり、彼らの関係、具体的には、\(私は\)チームがあり、シーズンの総支出の\ (^ 2 + D_IタイムズC_I \ X \ Y ^ 2回、D_I \ルC_I \) (マルチウェル上の選手に多くの賞金を獲得するために、)\(X、Yの\は)唯一のチームに今シーズン、スクリーニングの結果を表しています。今シーズンは各チームが作られた、半分に達した(a_iを\)\\(b_i \)敗北。そして、そこに\(m個\)があることを一致します。リーグのチームが求める最低限の総支出はどのくらいです。

入力

最初の行\(N、Mの\)
次に\(N- \)線各\(4 \)整数\(a_iを、b_i、C_I、
D_I \) 、次いで、次の\(Mの\)線各2整数\(S \)、\ (のt \)を表し\(複数可\)の注目は、2つのチームの間で複数のゲームであってもよいし、チームとTTのチーム間の試合があるでしょう。

出力

リーグと収益のすべてのチームの最小値を表す整数。

サンプル入力

3 3
1 0 2 1
1 1 10 1
0 1 3 3
1 2
2 3
3 1

サンプル出力

43

ヒント

对于20%的数据\(Mの\ 20 \ \ 10.0 \ 2 \ K) ;
100%对于的数据1000.0 \ \ M \ 5000.0 \ \(2 \ K D_I \ C_I \ a_iを\ 10.0、b_i \ 50 \)

分析

  • すべてのゲーム2つのチームが否定していると仮定すると、最初のリターンを計算します。
  • 各ゲーム、1つのチームの勝利を考えてみましょう。
    • \(ソースS \)する(Iゲーム\)を\接続された容量の側1,0のコスト。
    • その後、増分費用を考慮してください。収入はより生成されたゲームに勝ちます。その\((C×(W + 1)^ 2 + D *(L-1)^ 2) - (C *とW ^ 2 + D * L ^ 2)= 2ワット* C-2L * D + C + D \) 。
      • チームのために、想定した後\(M \)参加フィールド\(X \)フィールドを、その後、最初の\(W =勝利は、L = X + \を失う)、それぞれが勝利した後++ワット\(、Lを- 〜 - \) 。
      • 我々\(チーム\)には、(T \シンク)\でも\(X \)勝っ表す、エッジ\(J \)ゲームに勝つために相対的な\(J-1 \)フィールドをとき収入が増加します。
      • 増加によるものなので、我々は正確さを保証することができます。
  • \(ANS = \)すべてのチーム最初の利益\(+ \)最小コスト最大フローコスト。
  • 配列の範囲は、そうでない場合は、慎重に検討評価の予期しない結果を享受します。

コード

#include<bits/stdc++.h>
using namespace std;
const int maxn=5010,maxm=6010,maxe=1e5+10,inf=0x3f3f3f3f;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
    if (!x) *fe++=48;
    if (x<0) *fe++='-', x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) *fe++=ch[num--];
    *fe++='\n';
}

int ver[maxe],edge[maxe],Next[maxe],cost[maxe],head[maxm],len=1;
inline void add(int x,int y,int z,int c)
{
    ver[++len]=y,edge[len]=z,cost[len]=c,Next[len]=head[x],head[x]=len;
    ver[++len]=x,edge[len]=0,cost[len]=-c,Next[len]=head[y],head[y]=len;
}

int s,t;
int dist[maxm];
bool vis[maxm];
inline bool spfa()
{
    memset(dist,0x3f,sizeof(dist));
    memset(vis,0,sizeof(vis));
    queue<int>q;q.push(s);
    dist[s]=0,vis[s]=1;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for (int i=head[x]; i; i=Next[i])
        {
            if (!edge[i]) continue;
            int y=ver[i];
            if (dist[y]>dist[x]+cost[i])
            {
                dist[y]=dist[x]+cost[i];
                if (!vis[y]) q.push(y),vis[y]=1;
            }
        }
    }
    if (dist[t]==inf) return false;
    else return true;
}

int ans;
inline int get(int x,int low)
{
    vis[x]=1;
    if (x==t) return low;
    int tmp=low;
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (edge[i] && dist[y]==dist[x]+cost[i] && (!vis[y] || y==t))
        {
            int a=get(y,min(tmp,edge[i]));
            if (a>0)
            {
                ans+=a*cost[i];
                edge[i]-=a;
                edge[i^1]+=a;
                if (!(tmp-=a)) break;
            }
        }
    }
    return low-tmp;
}

inline void NetFlow()
{
    while (spfa())
    {
        vis[t]=1;
        while (vis[t])
        {
            memset(vis,0,sizeof(vis));
            get(s,inf);
        }
    }
}

typedef int iarr[maxn];
iarr win,lose,c,d,In;
int main()
{
    int n,m;read(n);read(m);
    s=0,t=n+m+1;
    for (int i=1; i<=n; ++i) read(win[i]),read(lose[i]),read(c[i]),read(d[i]);
    for (int i=1,x,y; i<=m; ++i) add(s,i,1,0),read(x),read(y),add(i,x+m,1,0),add(i,y+m,1,0),++In[x],++In[y];
    for (int i=1; i<=n; ++i) lose[i]+=In[i];
    for (int i=1; i<=n; ++i) ans+=win[i]*win[i]*c[i]+lose[i]*lose[i]*d[i];//直接计算初始收益
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=In[i]; ++j) add(i+m,t,1,2*c[i]*win[i]+c[i]+d[i]-2*d[i]*lose[i]),--lose[i],++win[i];
    NetFlow();
    write(ans);
    flush();
    return 0;
}

おすすめ

転載: www.cnblogs.com/G-hsm/p/11318051.html