CodeForces 164C Machine Programming 费用流

Machine Programming

题目连接:

http://codeforces.com/problemset/problem/164/B

Descriptionww.co

One remarkable day company "X" received k machines. And they were not simple machines, they were mechanical programmers! This was the last unsuccessful step before switching to android programmers, but that's another story.

The company has now n tasks, for each of them we know the start time of its execution si, the duration of its execution ti, and the company profit from its completion ci. Any machine can perform any task, exactly one at a time. If a machine has started to perform the task, it is busy at all moments of time from si to si + ti - 1, inclusive, and it cannot switch to another task.

You are required to select a set of tasks which can be done with these k machines, and which will bring the maximum total profit.

Input

The first line contains two integer numbers n and k (1 ≤ n ≤ 1000, 1 ≤ k ≤ 50) — the numbers of tasks and machines, correspondingly.

The next n lines contain space-separated groups of three integers si, ti, ci (1 ≤ si, ti ≤ 109, 1 ≤ ci ≤ 106), si is the time where they start executing the i-th task, ti is the duration of the i-th task and ci is the profit of its execution.

Output

Print n integers x1, x2, ..., xn. Number xi should equal 1, if task i should be completed and otherwise it should equal 0.

If there are several optimal solutions, print any of them.

Sample Input

3 1

2 7 5

1 3 3

4 1 3

Sample Output

0 1 1

Hint

题意

有n个任务,m个机器,每个机器同一时间只能处理一个任务

每个任务开始时间为s,持续时间为t,做完可以赚c元

问你做哪几个任务可以拿到最多的钱

输出方案

题解:

费用流

离散化每个任务的开始时间和结束时间,然后建图跑一遍就好了

把所有时间扔到一个队列里面排序

然后建立源点到最开始任务的起始时间-第二个时间-第三个时间-....-最后一个时间点-汇点,期间流量都是m,花费为0

然后对于每一个任务,连一条开始时间到结束时间+1的边,花费为-c,流量为1的

然后这样跑费用流一定就是答案了

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 10000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to, next, cap, flow, cost;
    int id;
    int x, y;
} edge[MAXM],HH[MAXN],MM[MAXN];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N, M;
void init()
{
    N = MAXN;
    tol = 0;
    memset(head, -1, sizeof(head));
}
int addedge(int u, int v, int cap, int cost, int id)//左端点,右端点,容量,花费
{
    edge[tol]. to = v;
    edge[tol]. cap = cap;
    edge[tol]. cost = cost;
    edge[tol]. flow = 0;
    edge[tol]. next = head[u];
    edge[tol]. id = id;
    int t = tol;
    head[u] = tol++;
    edge[tol]. to = u;
    edge[tol]. cap = 0;
    edge[tol]. cost = -cost;
    edge[tol]. flow = 0;
    edge[tol]. next = head[v];
    edge[tol]. id = id;
    head[v] = tol++;
    return tol;
}
bool spfa(int s, int t)
{
    queue<int>q;
    for(int i = 0; i < N; i++)
    {
        dis[i] = INF;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i]. next)
        {
            int v = edge[i]. to;
            if(edge[i]. cap > edge[i]. flow &&
                    dis[v] > dis[u] + edge[i]. cost )
            {
                dis[v] = dis[u] + edge[i]. cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1) return false;
    else return true;
}
//返回的是最大流, cost存的是最小费用
int minCostMaxflow(int s, int t, int &cost)
{
    int flow = 0;
    cost = 0;
    while(spfa(s,t))
    {
        int Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
        {
            if(Min > edge[i]. cap - edge[i]. flow)
                Min = edge[i]. cap - edge[i]. flow;
        }
        for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
        {
            edge[i]. flow += Min;
            edge[i^1]. flow -= Min;
            cost += edge[i]. cost * Min;
        }
        flow += Min;
    }
    return flow;
}
struct node
{
    int st,et,ct;
    int id;
}task[MAXN];
bool cmp(node A,node B)
{
    if(A.st==B.st)return A.et<B.et;
    return A.st<B.st;
}
map<int,int> H;
vector<int> V;
int id[3000];
int main()
{
    int n, m;
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&task[i].st,&task[i].et,&task[i].ct);
        task[i].et+=task[i].st-1;
        task[i].id=i;
        V.push_back(task[i].st);
        V.push_back(task[i].et);
    }

    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());

    for(int i=0;i<V.size();i++)
        H[V[i]]=i+1;
    for(int i=1;i<=V.size();i++)
        addedge(i-1,i,m,0,0);
    addedge(V.size(),V.size()+1,m,0,0);
    addedge(V.size()+1,V.size()+2,m,0,0);
    for(int i=1;i<=n;i++)
        id[i]=addedge(H[task[i].st],H[task[i].et]+1,1,-task[i].ct,i);
    int ans1=0,ans2=0;
    ans1=minCostMaxflow(0,V.size()+2,ans2);
    //printf("%d\n",ans2);
    for(int i=1;i<=n;i++)
        printf("%d ",edge[id[i]-2].flow);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值