1. 程式人生 > >[最大費用流]CCPC-Wannafly Summer Camp A:Birthday

[最大費用流]CCPC-Wannafly Summer Camp A:Birthday

恬恬的生日臨近了。宇揚給她準備了一個蛋糕。

正如往常一樣,宇揚在蛋糕上插了n支蠟燭,並把蛋糕分為m個區域。因為某種原因,他必須把第i根蠟燭插在第ai個區域或第bi個區域。區域之間是不相交的。宇揚在一個區域內同時擺放x支蠟燭就要花費x2的時間。宇揚佈置蛋糕所用的總時間是他在每個區域花的時間的和。

輸入

第一行包含兩個整數nm(1 ≤ n ≤ 50, 2 ≤ m ≤ 50)。

接下來n行,每行兩個整數aibi(1 ≤ aibi ≤ m)。

輸出

一個整數表示答案.

 

思路:

看下去毫無思路以為是dp,後面發現是網路流

把每一區域拆成50個點,再將可以該區域可以插的蠟燭分別與50個點連流量為1,費用依次為1,3,5,7......99((x+1)^2-x^2=2x+1)這樣的話從該區域流出的費用剛好為流入該區域的蠟燭的數量的平方。然後源點連每一個蠟燭,流量為1,費用為0,區域的每一個點連匯點,流量為1,費用為0,然後跑費用流就行了。

#include<bits/stdc++.h>
using namespace std;
const int inf=2147483647;//2^31-1
const int INF=1061109567;//一般設為無窮大
const int maxn = 1e5+5;
struct node{
    int u;
    int v;
    int c;
    int w;
    int next;
}edge[maxn];
int n,m,sp,tp,ednum=0;
int a[maxn];
int b[maxn];
int dis[maxn];
int pre[maxn];
int pos[maxn];
int p[maxn];
int head[maxn];
bool vis[maxn];
queue<int>que;
void initialization()
{
    memset(head,-1,sizeof(head));
    ednum=0;
}
void Insert(int u,int v,int c,int w)
{
    edge[ednum].u=u;
    edge[ednum].v=v;
    edge[ednum].c=c;
    edge[ednum].w=w;
    edge[ednum].next=head[u];
    head[u]=ednum++;
}

bool spfa()
{
    memset(vis,true,sizeof(vis));
    memset(dis,63,sizeof(dis));
    vis[sp]=false;
    dis[sp]=0;
    p[sp]=inf;
    que.push(sp);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        vis[u]=true;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(edge[i].c>0&&dis[v]>dis[u]+edge[i].w)
            {
                dis[v]=dis[u]+edge[i].w;
                pos[v]=u;
                pre[v]=i;
                p[v]=min(p[u],edge[i].c);
                if(vis[v])
                {
                    que.push(v);
                    vis[v]=false;
                }
            }
        }
    }
    return dis[tp]<INF;
}
int flow()
{
   int ans=0;
    while(spfa())
    {
        ans+=p[tp]*dis[tp];
      //  cout<<ans<<"    AAAAAAA"<<endl;
        for(int i=tp;i!=sp;i=pos[i])
        {
            edge[pre[i]].c-=p[tp];
            edge[pre[i]^1].c+=p[tp];
        }
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    initialization();
    sp = 0;
    tp = 50*60;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        Insert(sp,i,1,0);
        Insert(i,sp,0,0);
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= 50; j++)
        {
          //  cout<<i<<"    SSS    "<<a[i]*50+j<<endl;
            Insert(i, a[i]*50+j, 1, 0);

            Insert(a[i]*50+j, i, 0, 0);

            Insert(i, b[i]*50+j, 1, 0);

            Insert(b[i]*50+j, i, 0, 0);
        }
    }
    int ind = 0;
    for(int i = 51;i<=2550;i++)
    {
        ind++;
        Insert(i, tp, 1, 2*ind-1);
        Insert(tp, i, 0, -2*ind+1);
      //  cout<<2*ind-1<<"  DDDD      "<<i<<endl;
        ind%=50;
    }
    int ans1 = flow();
    printf("%d\n",ans1);
}