Kattis - catering(WF2015)(有源汇有上下界费用可行流)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/83154382

Paul owns a catering company and business is booming. The company has kk catering teams, each in charge of one set of catering equipment. Every week, the company accepts nn catering requests for various events. For every request, they send a catering team with their equipment to the event location. The team delivers the food, sets up the equipment, and instructs the host on how to use the equipment and serve the food. After the event, the host is responsible for returning the equipment back to Paul’s company.

Unfortunately, in some weeks the number of catering teams is less than the number of requests, so some teams may have to be used for more than one event. In these cases, the company cannot wait for the host to return the equipment and must keep the team on-site to move the equipment to another location. The company has an accurate estimate of the cost to move a set of equipment from any location to any other location. Given these costs, Paul wants to prepare an Advance Catering Map to service the requests while minimizing the total moving cost of equipment (including the cost of the first move), even if that means not using all the available teams. Paul needs your help to write a program to accomplish this task. The requests are sorted in ascending order of their event times and they are chosen in such a way that for any i<ji<j, there is enough time to transport the equipment used in the ithith request to the location of the jthjth request.

Input

The first line of input contains two integers nn (1≤n≤1001≤n≤100) and kk (1≤k≤1001≤k≤100) which are the number of requests and the number of catering teams, respectively. Following that are nn lines, where the ithith line contains n−i+1n−i+1 integers between 00and 10000001000000 inclusive. The jthjth number in the ithith line is the cost of moving a set of equipment from location ii to location i+ji+j. The company is at location 11 and the nnrequests are at locations 22 to n+1n+1.

Output

Display the minimum moving cost to service all requests. (This amount does not include the cost of moving the equipment back to the catering company.)

Sample Input 1 Sample Output 1
3 2
40 30 40
50 10
50
80
Sample Input 2 Sample Output 2
3 2
10 10 10
20 21
21
40

题意:

有一家装备出租公司收到了按照时间顺序排列的n个请求.

这家公司有k个搬运工.每个搬运工可以搬着一套装备按时间顺序去满足一些请求.一个搬运工从第i个请求的位置把东西搬到第j个请求的位置需要一些费用.公司的编号是1,请求的编号是2到n+1.所有搬运工必需从公司出发.

求满足所有请求所需的最小搬运费用.

解题思路:有源汇上下界费用流

上下界网络流:新建超超级源点ss,超超级汇点tt。对于有上下界(b,c)的边,新建

一条为<ss,v>,容量为b的边;

一条为<u,tt>,容量为b的边;

一条为<u,v>,容量为c−b的边。

然后因为有源汇,再新建一条

<t,s>,容量下界为0,上界为∞的边

然后加上费用就可以跑费用流了。

关于这题:

将每个点拆成两个,之间连边,上下界均为1。

用一个单独的点连向1限制流量,再加入两点之间的边。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 50005;
const int INF = 0x3f3f3f3f;

struct edge
{
    int u, v, cap, cost, next;
} e[4 * MAXN];

int edge_num;
int head[300];

void insert_edge(int u, int v, int cap, int cost)
{
    e[edge_num].u = u;
    e[edge_num].v = v;
    e[edge_num].cap = cap;
    e[edge_num].cost = cost;
    e[edge_num].next = head[u];
    head[u] = edge_num++;

    //反向边 k^1即可求出反向边
    e[edge_num].u = v;
    e[edge_num].v = u;
    e[edge_num].cap = 0;      //注意这里
    e[edge_num].cost = -cost; //注意这里
    e[edge_num].next = head[v];
    head[v] = edge_num++;
}

int dis[300];
int pre[300];
bool vis[300];
bool spfa(int s, int t)
{
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));

    dis[s] = 0;
    vis[s] = 1;
    queue<int> que;
    que.push(s);
    while (!que.empty())
    {
        int tp = que.front();
        que.pop();
        vis[tp] = 0;
        for (int i = head[tp]; ~i; i = e[i].next)
        {
            int v = e[i].v;
            int cost = e[i].cost;

            if (e[i].cap && dis[v] > dis[tp] + cost)
            {
                dis[v] = dis[tp] + cost;
                pre[v] = i;
                if (!vis[v])
                {
                    vis[v] = 1;
                    que.push(v);
                }
            }
        }
    }
    if (dis[t] == INF)
        return false;
    return true;
}

pair<int, int> MCMF(int s, int t)
{
    int maxflow = 0;
    int mincost = 0;
    int minc;
    while (spfa(s, t))
    {
        minc = INF;
        int cost = 0;
        for (int i = pre[t]; ~i; i = pre[e[i].u])
            minc = min(minc, e[i].cap);
        for (int i = pre[t]; ~i; i = pre[e[i].u])
        {
            e[i].cap -= minc;
            e[i ^ 1].cap += minc;
            cost += minc * e[i].cost; //flow*unit cost=total cost
        }
        mincost += cost;
        maxflow += minc;
    }
    return make_pair(mincost, maxflow);
}


int N,K;
int SX[MAXN];
int SY[MAXN];
int C[105][105];
int cnt=0;
int main()
{
    edge_num=0;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&N,&K);

    //建点
    int s=++cnt;
    int t=++cnt;
    int S=++cnt;
    int T=++cnt;
    for(int i=1;i<=N+1;i++){
        SX[i]=++cnt;
        SY[i]=++cnt;
    }

    for(int i=1;i<=N;i++){
        for(int j=1;j<=(N-i)+1;j++){
            scanf("%d",&C[i][i+j]);
            C[i+j][i]=C[i][i+j];
        }
    }

    //建边
    insert_edge(S,SX[1],K,0);
    for(int i=2;i<=N+1;i++)
        insert_edge(SX[1],SX[i],INF,C[1][i]);
    for(int i=2;i<=N+1;i++){
        insert_edge(s,SY[i],1,0);
        insert_edge(SX[i],t,1,0);
        insert_edge(SY[i],T,INF,0);
    }
    insert_edge(T,S,INF,0);
    for(int i=2;i<=N;i++)
        for(int j=i+1;j<=N+1;j++)
            insert_edge(SY[i],SX[j],INF,C[i][j]);

    printf("%d\n",MCMF(s,t).first);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/83154382