Monkeys in the Emei Mountain -- UVA - 11167 (网络流)

Monkeys in the Emei Mountain 
Input: Standard Input

Output: Standard Output

Xuexue is a pretty monkey living in the Emeimountain. She is extremely thirsty during time 2 and time 9 everyday, so she must drink 2 units water during this period. She may drink water more than once, as long as the total amount of water she drinks is exactly 2 - she never drinks more than she needs.  Xuexuedrinks 1 unit water in one time unit, so she may drinks from time 2 to time 4, or from 3 to 5, … , or from 7 to 9, or even drinks twice: first from 2 to 3, then from 8 to 9. But she can't drink from 1 to 3 since she's not thirsty at time 1, and she can't drink from 8 to 10, since she must finish at time 9.

 

There are many monkeys like Xuexue: we use a triple (vab) to describe a monkey who is thirsty during time a andb, and must drink exactly v units of water during that period. Every monkey drinks at the same speed (i.e. one unit water per unit time).

 

Unfortunately, people keep on doing something bad on the environment in Emei Mountain . Eventually, there are only one unpolluted places for monkeys to drink. Further more, the place is so small that at most m monkeys can drink water together. Monkeys like to help each other, so they want to find a way to satisfy all the monkeys' need. Could you help them?

 

Input

The input consists of several test cases. Each case contains two integers and (1 ££ 100, 1 ££ 5), followed by n lines of three integer numbers (va,b), where 0 £v, a, b £ 50,000, a < b, v £b - a. The last test case is followed by a single zero, which should not be processed. There are at most 50 test cases.

 

Output

For each test case, print the case number and whether there is a solution. If there is a solution, the following n lines describe the solution: one monkey on a separate line. The first number k means the monkey drinks water for k times. The following k pairs (aibi) means the monkey drinks from ai to b(aibi). The pairs should be sorted in ascending order, and ai should not be equal to ai+1 for 1£i£k-1 (otherwise these two drinking periods could be combined). If more than one solution exists, any one is acceptable. Note that there should be exactly one space between k and pairs (ai,bi), but no space within each pair.

Sample Input                               Output for Sample Input

3 1

2 2 9

2 3 5

3 5 8

2 1

4 5 9

4 8 12

5 2

2 1 3

2 3 5

2 5 7

2 1 7

4 2 6

0

Case 1: Yes

2 (2,3) (8,9)

1 (3,5)

1 (5,8)

Case 2: No

Case 3: Yes

1 (1,3)

1 (3,5)

1 (5,7)

2 (1,2) (6,7)

1 (2,6)


题目大意:

有N个猴子要在a-b的时间区间喝够v升的水。每只猴子喝水的速度都是一小时一升水。可以不需要连续喝水。但是必须以一小时为最小单位。

现在有一个地方 可以同时供m个猴子去喝水。问最终能否有喝水的方案,如果有输出方案。

思路:

由于时间跨度很大,但是N很小。所以可以将时间离散化。离散为不超过2*N个区间。

然后建立二分图,X部为猴子,源点向其连一条容量为a[i].v的边。Y部为每个时间区间。因为每个小时最多可以有m个猴子喝水 所以连接到汇点,容量为m*(区间长度)

然后判断每一个猴子的喝水区间,如果包含离散化出的时间区间。表示这只猴子可以在这个时间区间喝水。连边,容量为区间长度。

最大流的结果如果使得X部满流,说明每只猴子都可以喝到水。输出方案,否则无解。


输出方案:

我觉得这道题最麻烦的就是输出方案的说。

由于一个区间可能由多个猴子同时分享,使得简单的判断反向边的残量的做法失效。

用now数组表示每一个时间区间,如果某个区间消耗掉了f个时间,那么now[i]+= f;当now+f大于了这个区间的终点,说明已经是后面的猴子来喝水了,那么循环重置一下就好。这部分具体看代码。

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define maxn 1111
#define maxm 1000000
#define INF 0x3f3f3f3f
using namespace std;


struct Edge
{
    int from,to,next,f;
}es[maxm];
struct Node
{
    int v,a,b;
}a[1111];

int b[1111];
int len,sum,ks;
int cnt,p[maxn];
int n,m,s,t,ans_f;
int dis[maxn],cur[maxn];


void add(int from,int to,int f)
{
    es[cnt].from = from;
    es[cnt].to = to;
    es[cnt].f = f;
    es[cnt].next = p[from];
    p[from] = cnt++;

    es[cnt].from = to;
    es[cnt].to = from;
    es[cnt].f = 0;
    es[cnt].next = p[to];
    p[to] = cnt++;
}

bool bfs()
{
    memset(dis,0,sizeof dis);
    dis[s] = 1;
    queue <int > q;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        if(u == t) return true;
        q.pop();
        for(int i = p[u];~i;i = es[i].next)
        {
            int v = es[i].to;
            if(dis[v] || !es[i].f) continue;
            dis[v] = dis[u]+1;
            q.push(v);
        }
    }
    return false;
}


int dfs(int x,int a)
{
    if(x == t) return a;
    int flow = 0;
    for(;cur[x]+1;cur[x] = es[cur[x]].next)
    {
        Edge &e = es[cur[x]];
        if(e.f && dis[e.to] == dis[x]+1)
        {
            int f = dfs(e.to,min(a-flow,e.f));
            flow += f;
            e.f -= f;
            es[cur[x]^1].f += f;
            if(flow == a) return flow;
        }
    }
    return flow;
}

void init()
{
    ks++;
    len = 0;
    sum = 0;
    memset(p,-1,sizeof p);
    memset(a,0,sizeof a);
    memset(b,0,sizeof b);
    cnt =0;
}

void Maxflow(int num)
{
    ans_f = 0;
    while(bfs())
    {
        for(int i = 0;i <= num;i++) cur[i] = p[i];
        ans_f += dfs(s,INF);
    }

}
int now[1010];
int ans[1010];

void put()
{
    int len = 0;
    for(int u = 1; u <= n; ++u)
    {
        len = 0;
        for(int i = p[u]; ~i; i = es[i].next)
        {
            int v = es[i].to, f = es[i^1].f;
            if(f)
            {
                ans[len++] = now[v - n];
                if(now[v-n] + f > b[v-n])
                {
                    ans[len++] = b[v-n];
                    ans[len++] = b[v-1-n];
                    ans[len++] = b[v-1-n] + f - (b[v-n] - now[v-n]);
                    now[v-n] = ans[len-1];
                }
                else now[v-n] += c, ans[len++] = now[v-n];
                if(now[v-n] == b[v-n]) now[v-n] = b[v-1-n];
            }
        }
        int _len = 0;
        for(int i = 1; i < len; ++i)
        {
            if(ans[i] == ans[_len])
                ans[_len] = ans[i+1], ++i;
            else
                ans[++_len] = ans[i];
        }
        len = _len + 1;
        printf("%d", len / 2);
        for(int i = 0; i < len; i += 2)
            printf(" (%d,%d)", ans[i], ans[i+1]);
        printf("\n");
    }
}



int main()
{
    while(scanf("%d",&n),n)
    {
        scanf("%d",&m);
        init();
        for(int i = 1;i <= n;i++)
        {
            scanf("%d %d %d",&a[i].v,&a[i].a,&a[i].b);
            b[len++] = a[i].a;
            b[len++] = a[i].b;
            sum += a[i].v;
        }
        sort(b,b+len);
        len = unique(b,b+len)-b;
        s = 0,t = n+len+1;
        for(int i = 1;i <= n;i++) add(s,i,a[i].v);
        for(int i = 1;i < len;i++) add(n+i,t,m*(b[i]-b[i-1]));
        for(int i = 1;i < len;i++) now[i] = b[i-1];
        for(int i = 1;i <= n;i++)
        {
            for(int j = 1;j < len;j++)
            {
                if(a[i].a <= b[j-1] && a[i].b >= b[j])
                    add(i,n+j,b[j]-b[j-1]);
            }
        }
        Maxflow(t);

        if(sum == ans_f)
        {
            printf("Case %d: Yes\n",ks);
            put();
        }
        else
        {
            printf("Case %d: No\n",ks);
        }
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值