2017-2018 ACM-ICPC Southwestern European Regional Programming Contest (SWERC 2017) G: Cordon Bleu

Cordon Bleu

时间限制: 1 Sec  内存限制: 128 MB
提交: 22  解决: 7
[提交][状态][讨论版][命题人:admin]

题目描述

A Parisian entrepreneur has just opened a new restaurant “Au bon cordon bleu”, named after a famous French recipe. However, no one has any idea of which wine would be appropriate with such a dish.The entrepreneur plans to sample many different wines in order to build the wine menu.
The various bottles of wine he plans to taste can be obtained from different wine merchants located in or around Paris. Being a very sensitive product, high-quality wine can only be transported by highly trained couriers on motorbikes. Therefore, those couriers are very expensive.
A courier can be used for the transportation of several wine bottles, but can transport only one bottle at a time. All couriers get paid at the same fixed rate: one euro per kilometer. The distance function used is the Manhattan distance (also known as taxicab metric) of every individual segment of the trip:
the distance from a point (x1, y1) to a point (x2, y2) is |x1 − x2| + |y1 − y2|.
A courier in charge of transporting a single wine bottle will get paid as many euros as the sum of the following two (Manhattan) distances: from her base to the wine merchant place, and from the wine merchant place to the restaurant.
Consider a more complex example: a courier in charge of transporting two wine bottles, one after the other. The amount paid will be the sum of the following distances: from his base to the location of the first bottle, then to the restaurant, then to the location of the second bottle, then to the restaurant. 
Help the entrepreneur minimize the costs of hiring the couriers. Given a set of Cartesian coordinates corresponding to available couriers, a set of Cartesian coordinates corresponding to the locations of the precious wine bottles they need to collect, and the location of the restaurant, compute the smallest number of kilometers that the couriers will be paid for. There is no obligation to use all available couriers, and bottles can be collected in an arbitrary order.

输入

The input comprises several lines, each consisting of integers separated with single spaces:
• The first line consists of the number N of wine bottles to collect and the number M of available couriers.
• The N following lines consist of the coordinates of each bottle as two integers x and y.
• The M following lines consist of the coordinates of each courier’s base as two integers x and y.
• The last line contains the coordinates of the restaurant as two integers x and y.
Limits
• 1≤N≤1 000;
• 1≤M≤1 000;
• all coordinates (x, y) verify −1 000≤x≤1 000 and −1 000≤y≤1 000.

输出

A single integer: the smallest number of euros that needs to be paid to collect all bottles.

样例输入

2 2

1 0

0 -1

-1 1

2 -1

0 0

样例输出

5

提示

There might be more than one item at the same initial location. For example, it would be possible for two bottles, ten couriers, and the restaurant to share the same starting position.

On this example, only one courier (C2) is used to retrieve the two bottles B1 and B2, and bring them to the restaurant R by performing the moves labeled 1 to 4 in succession. The total number of kilometers is 5. This is one of the optimal solutions.

来源


[思路]

    题意大概,  n个酒,m个人,  一个餐馆,现在  一个人可以把2瓶酒送到餐馆,

    但是 送货要求是:  人的起点-> 第一个酒-> 餐馆-> 第二个酒 -> 餐馆

    注意:人第二次把酒 送到餐馆后,就在餐馆了, 可以再从餐馆在出发 去取另外的酒;

    最小费用流,网络流,  


抽象这样一个图,

源点到酒, 容量为1, 花费为0

人到汇点  容量为1, 花费为0 

餐馆到 汇点 容量为(n-1)  花费为0  : 注意 不是n  而是 n-1: 解释,  这一部分其实 是 第二瓶酒到餐馆,  

如果容量为n的话, 那么, 相当于 酒自己跑过去了,最少得有个人去取才对.


但是但是 (n^2) 的 建图 在 cf 是会超时的,  复杂度 太高,  在 UPC上可以过去,(数据真水, )  (CF数据是真强)

建图必须优化到 nlogn 内才可以,  大牛的 操作是 


emmmm.. 可持久化线段树 ???? , 暂时不会......  弱鸡真菜,,,

留个坑, 以后补,  可持久化线段树

[贴一个 n^2 的  水一下  ,  就当过了把]

#include <iostream>
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a));
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN = 1e4 +7 ;
const int maxn = 1e6+7;
using namespace std;

struct node{
    int u,v,w,c,next;
}edge[maxn];
struct Pnode
{
    int x,y;
}win[MAXN],men[MAXN];
int  Dis(Pnode a,Pnode b)
{
    return ( abs(a.x-b.x) + abs(a.y-b.y));
}

int head[maxn],start,END,cnt,sum;
int dis[maxn],pre[maxn],vis[maxn];

void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int c,int w)
{
    // c 容量 w权值
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].c=c;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    // 有向图, 反射边 cost = -cost
    edge[cnt].u=v;
    edge[cnt].v=u;
    edge[cnt].w=-w;
    edge[cnt].c=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;

}

int SPFA()
{
    queue<int>Q;
    mem(pre,-1);
    mem(vis,0);
    mem(dis,INF);
    dis[start]=0;
    vis[start]=1;
    Q.push(start);
    while(!Q.empty())
    {
        int t=Q.front();
        Q.pop();
        vis[t]=0;
        for(int i=head[t];i!=-1;i=edge[i].next)//
        {
            int t1= edge[i].v;//下一个点
            int t2= edge[i].w;// 费用
            if(edge[i].c&&dis[t1]>dis[t]+t2)// 最短路
            {
                dis[t1]=dis[t]+t2;
                pre[t1]=i;
                if(!vis[t1])
                {
                    Q.push(t1);
                    vis[t1]=1;
                }
            }
        }
    }
    if(dis[END]==INF)return 0;
    return 1;
}
int MCMF()
{
    int minflow=0;
    int mincost=0;
    while(SPFA())
    {
        minflow=INF;
        for(int i=pre[END];i!=-1;i=pre[edge[i].u])
        {
            minflow=min(minflow,edge[i].c);
        }
        for(int i=pre[END];i!=-1;i=pre[edge[i].u])
        {
            edge[i].c-=minflow;
            edge[i^1].c+=minflow;
        }
        mincost+=dis[END];
    }
    return mincost;
}

int main()
{
    int n,m;
    init();
    cin>>n>>m;
    start = 0;
    END = n+m+12;
    for(int i = 1 ;i<=n;i++)
        cin>>win[i].x>>win[i].y;
    for(int i = 1 ;i<=m;i++)
        cin>>men[i].x>>men[i].y;
    Pnode e;
    cin>>e.x>>e.y;
    for(int i=1;i<=n;i++)
    {
        add(start,i,1,0);// st->i
        for(int j=1;j<=m;j++)
        {
            int w=Dis(win[i],men[j])+Dis(win[i],e);
            add(i,1001+j,1,w);// wine->ren+ wine-> dir
        }
        add(i,1001+m+1,1,2*Dis(win[i],e));// wine->dir *2
    }
    for(int j=1;j<=m;j++)// men-> END
    {
        add(1001+j,END,1,0);
    }
    add(1001+m+1,END,n-1,0);// dir-> END;
    int ans=MCMF();
    cout<<ans<<endl;
    return 0;
}

12

posted @ 2018-04-30 20:52  Sizaif  阅读(484)  评论(0编辑  收藏  举报