C. Chef Monocarp - 费用流

Problem - 1437C - Codeforces

C. Chef Monocarp

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Chef Monocarp has just put nn dishes into an oven. He knows that the ii-th dish has its optimal cooking time equal to titi minutes.

At any positive integer minute TT Monocarp can put no more than one dish out of the oven. If the ii-th dish is put out at some minute TT, then its unpleasant value is |T−ti||T−ti| — the absolute difference between TT and titi. Once the dish is out of the oven, it can't go back in.

Monocarp should put all the dishes out of the oven. What is the minimum total unpleasant value Monocarp can obtain?

Input

The first line contains a single integer qq (1≤q≤2001≤q≤200) — the number of testcases.

Then qq testcases follow.

The first line of the testcase contains a single integer nn (1≤n≤2001≤n≤200) — the number of dishes in the oven.

The second line of the testcase contains nn integers t1,t2,…,tnt1,t2,…,tn (1≤ti≤n1≤ti≤n) — the optimal cooking time for each dish.

The sum of nn over all qq testcases doesn't exceed 200200.

Output

Print a single integer for each testcase — the minimum total unpleasant value Monocarp can obtain when he puts out all the dishes out of the oven. Remember that Monocarp can only put the dishes out at positive integer minutes and no more than one dish at any minute.

Example

input

Copy

6
6
4 2 4 4 5 2
7
7 7 7 7 7 7 7
1
1
5
5 1 2 4 3
4
1 4 4 4
21
21 8 1 4 1 5 21 1 8 21 11 21 11 3 12 8 19 15 9 11 13

output

Copy

4
12
0
0
2
21

Note

In the first example Monocarp can put out the dishes at minutes 3,1,5,4,6,23,1,5,4,6,2. That way the total unpleasant value will be |4−3|+|2−1|+|4−5|+|4−4|+|6−5|+|2−2|=4|4−3|+|2−1|+|4−5|+|4−4|+|6−5|+|2−2|=4.

In the second example Monocarp can put out the dishes at minutes 4,5,6,7,8,9,104,5,6,7,8,9,10.

In the third example Monocarp can put out the dish at minute 11.

In the fourth example Monocarp can put out the dishes at minutes 5,1,2,4,35,1,2,4,3.

In the fifth example Monocarp can put out the dishes at minutes 1,3,4,51,3,4,5.

=========================================================================

很显然的套路就是对人建立n个点,然后对数轴 1--2n建立虚点,并拆开虚点,来保证每个时间点只能用一次,且虚点之间的花费应该是1,然后把每个人的a[i] 直接连接在数轴的虚点位置上,且花费为0,这样就把人引进了数轴里面,然后无论向左走还是向右走,都是花费的正值,合起来就是绝对值了

# include<iostream>
# include<cstring>
# include<queue>
using namespace std;
int n,m,st,ed,len=2;
typedef long long int  ll;
typedef struct
{
    int b,e;
    ll flow,dis;
}xinxi;
xinxi s[101010];
int f[101010],nex[101010];
int pre[101010],vis[101010];
ll dis[101010],minn[101010];
ll mincost, maxflow;
queue<int>q;
void add(int x,int y,ll flow,ll dis)
{
    s[len].b=x;
    s[len].e=y;
    s[len].flow=flow;
    s[len].dis=dis;

    nex[len]=f[x];
    f[x]=len;
    len++;
}
ll inf=1e18;

bool SPFA()
{
    for(int i=1;i<=ed;i++)
    {
        vis[i]=0;
        dis[i]=inf;
    }
    q.push(st);
    minn[st]=inf;
    dis[st]=0;
    vis[st]=1;

    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        vis[now]=0;
        int x=f[now];
        while(x!=-1)
        {
            int j=s[x].e;
            if(s[x].flow==0)
            {
                x=nex[x];
                continue;
            }
            if(dis[j]>dis[now]+s[x].dis)
            {
                dis[j]=dis[now]+s[x].dis;
                minn[j]=min(minn[now],s[x].flow);

                pre[j]=x;

                if(!vis[j])
                {
                    vis[j]=1;
                    q.push(j);
                }
            }
            x=nex[x];
        }
    }

    return (dis[ed]!=inf);

}

void work()
{
    maxflow=0;
    mincost=0;
    while(SPFA())
    {
        int x=ed;

        maxflow+=minn[ed];
        mincost+=minn[ed]*dis[ed];
        int i;
        while(x!=st)
        {
            i=pre[x];
            s[i].flow-=minn[ed];
            s[i^1].flow+=minn[ed];
            x=s[i^1].e;
        }
    }
}

int a[210];
int main ()
{


   int t;
   cin>>t;

   while(t--)
   {
       cin>>n;
       len=2;
       memset(f,-1,sizeof(f));


       st=0;
       ed=2*n+2*n+n+1;
       for(int i=1;i<=n;i++)
       {
           cin>>a[i];
           add(st,i,1,0);
           add(i,st,0,0);


       }

       for(int i=n+1;i<=3*n;i++)
       {
           add(i,i+2*n,1,0);
           add(i+2*n,i,0,0);

           if(i==n+1)
           {
               add(i,i+1,inf,1);
               add(i+1,i,0,-1);
           }

           else if(i==3*n)
           {
               add(i,i-1,inf,1);
               add(i-1,i,0,-1);
           }
           else
           {
               add(i,i-1,inf,1);
               add(i-1,i,0,-1);
               add(i,i+1,inf,1);
               add(i+1,i,0,-1);
           }

           add(i+2*n,ed,1,0);
           add(ed,i+2*n,0,0);
       }
       for(int i=1;i<=n;i++)
       {

               int nowid=a[i]+n;

               add(i,nowid,1,0);
               add(nowid,i,0,0);

       }

       work();
       cout<<mincost<<endl;


   }


    return 0;

}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinsanma and Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值