Lightoj 1237 Cyber Cafe(费用流)

1237 - Cyber Cafe

   PDF (English)StatisticsForum
Time Limit: 2 second(s)Memory Limit: 32 MB

After graduating in CS, Mr 'AcmHateKori' has opened a cyber café. His business was running quite well unless one day he faced a problem, and with his non-ACM mind he was unable to solve that.

In his café he maintains two papers for his customers. One paper contains the entering times of the customers in the café and the other paper contains the times they have exited. He writes the times in the same order in the papers for the money calculations. And he only writes the nearest minute of the time. He writes the times from 0 to 1000 (0 means 12:00 am, 60 means 01:00 am, 730 means 02:10 pm). This idea was given by his little son.

When a person exits the café he was to pay some money. If he stays in the café for T minutes, he has to pay (T-K)2 paisa but not more than G paisa (if money exceeds G). It's guaranteed that every person stays at least one minute in the café.

Now one day his little son came to the café and took the paper that contained the entering times of the customers. He took a new paper and wrote the entering times randomly and threw the old paper. When his father came, he found two papers, where the first one contained some random entering times. He was at a loss and angry. Cause how can he find the total money given by the customers since for an entering time there can be multiple exiting times.

So, finally he realized the importance of ACM in life and asked you to find the minimum and maximum money he could earn by matching all entering times and exiting times. His son can be faulty. So, you have to report that too.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing three integers n (1 ≤ n ≤ 50), K (1 ≤ K ≤ 1000), G (0 ≤ G ≤ 10000) where n denotes the number of customers. The next line contains n space separated integers denoting the entering times of the customers. The next line contains n space separated integers denoting the exiting times of the customers. All the given times will lie in the range [0, 1000].

Output

For each case, print the case number, the minimum and maximum money he could earn or 'impossible' if his son had made some mistakes.

Sample Input

Output for Sample Input

2

3 7 11

8 9 10

9 11 20

2 10 10

1 11

2 9

Case 1: 31 33

Case 2: impossible

 题目大意:有n个人去咖啡店,老板将他们的进入时间和走的时间都记录下来了,但是弄混了,对于每个人来说,老板要收的钱是他在咖啡店待的时间T减去一个给出的常数K的差的平方,而且老板最多只收G元,超过G元也算G元,问最少收益和最大收益分别是多少

n^2建图,对于一个进入时间,找出符合的走的时间,连一条容量为1,费用为差值的平方的边,所有的进入时间与源点连一条容量为1,费用为0的边,所有的走的时间与汇点连一条容量为1,费用为0的边,跑一遍费用流,这时候得到的是最少费用。然后再重新建一次图,不同的是这一次进入时间与走的时间连的边费用取负数,然后也跑一遍费用流。如何判断impossible的情况,如果跑完费用流最后的总流量不等于n,就是impossible

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=510;
const int maxm=100010;
const int inf=0x3f3f3f3f;
struct Node
{
    int to;
    int capa;
    int cost;
    int next;
}edge[maxm];
int n,K,G;
int source,sink;
int cnt;
int head[maxn];
int dis[maxn];
bool vis[maxn];
int dep[maxn];
int numa[maxn];
int numb[maxn];
int pre[maxn];
int rec[maxn];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    return;
}
void add(int u,int v,int capa,int cost)
{
    edge[cnt].to=v;
    edge[cnt].capa=capa;
    edge[cnt].cost=cost;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].to=u;
    edge[cnt].capa=0;
    edge[cnt].cost=-cost;
    edge[cnt].next=head[v];
    head[v]=cnt++;
    return;
}
bool spfa()
{
    memset(vis,false,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    memset(rec,-1,sizeof(rec));
    memset(pre,-1,sizeof(pre));
    queue<int> que;
    que.push(source);
    dis[source]=0;
    vis[source]=true;
    while(!que.empty())
    {
        int node=que.front();
        que.pop();
        vis[node]=false;
        for(int i=head[node];~i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].capa>0&&dis[v]>dis[node]+edge[i].cost)
            {
                dis[v]=dis[node]+edge[i].cost;
                rec[v]=i;
                pre[v]=node;
                if(!vis[v])
                {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
    return dis[sink]!=inf;
}
int mcmf()
{
    int maxflow=0;
    int mincost=0;
    while(spfa())
    {
        int node=sink;
        int flow=inf;
        while(node!=source)
        {
            flow=min(flow,edge[rec[node]].capa);
            node=pre[node];
        }
        maxflow+=flow;
        node=sink;
        while(node!=source)
        {
            mincost+=flow*edge[rec[node]].cost;
            edge[rec[node]].capa-=flow;
            edge[rec[node]^1].capa+=flow;
            node=pre[node];
        }
    }
    if(maxflow!=n) return -1;
    return -mincost;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int test;
    scanf("%d",&test);
    for(int cas=1;cas<=test;cas++)
    {
        init();
        scanf("%d%d%d",&n,&K,&G);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&numa[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&numb[i]);
        }
        source=0;
        sink=n*2+1;
        init();
        for(int i=1;i<=n;i++)
        {
            add(source,i,1,0);
            add(i+n,sink,1,0);
            for(int j=1;j<=n;j++)
            {
                if(numb[j]>numa[i])
                {
                    int cost=((numb[j]-numa[i])-K)*((numb[j]-numa[i])-K);
                    add(i,j+n,1,cost>G?G:cost);
                }
            }
        }
        int min_ans=mcmf();
        init();
        for(int i=1;i<=n;i++)
        {
            add(source,i,1,0);
            add(i+n,sink,1,0);
            for(int j=1;j<=n;j++)
            {
                if(numb[j]>numa[i])
                {
                    int cost=((numb[j]-numa[i])-K)*((numb[j]-numa[i])-K);
                    add(i,j+n,1,cost>G?-G:-cost);
                }
            }
        }
        int max_ans=mcmf();
        if(min_ans==-1||max_ans==-1)
        {
            printf("Case %d: impossible\n",cas);
        }
        else
        {
            printf("Case %d: %d %d\n",cas,-min_ans,max_ans);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值