uva 11167 !wa! 区间压缩

Problem C
Monkeys in the Emei Mountain
Input: Standard Input

Output: Standard Output

 

Xuexue is a pretty monkey living in the Emei mountain. 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.  Xuexue drinks 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 (v, a, b) to describe a monkey who is thirsty during time a and b, 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 n and m (1 £ n £ 100, 1 £ m £ 5), followed by n lines of three integer numbers (v, a, 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 (ai, bi) means the monkey drinks from ai to bi (ai< bi). 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)


Original Author: Dong Zhou

Adapted by Rujia Liu (Problem description, Special judge)

Alternative Solution: Huayang Guo

 

WA掉的代码。。。

建模:区间压缩(interval contraction,很多题解叫“离散化”),然后把时间区间缩小至[1, 200),建立至多199个区间,每个长度为1(hash长度可能不同);

接着从源点引边至每个区间,容量为m*(hash[left+1] - hash[left]);从每个区间向可以在该时段解渴的猴子引容量为(hash[left+1] - hash[left])的边(记下这条边),从每只猴子向汇点引容量为饥渴度的边。。。

最后,枚举每只猴子对应的所有解渴时段,对应流量找可行区间(reverse hash / contraction)即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<map>

using namespace std;

#define LL long long
#define ULL unsigned long long
#define UINT unsigned int
#define MAX_INT 0x7fffffff
#define cint const int
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define INF 100000000
#define MAXN 310
#define MAXM 41000
#define MAXK 55555
#define MAX_MONKEY 111
#define MAX_INTERVAL 222

struct MON{
    int v, a, b;
}monkey[MAX_MONKEY];

int contract[MAXK];
int rcontract[MAX_INTERVAL];

struct edge{
    int u, v, cap, flow, nxt;
}e[MAXM];
int h[MAXN], cc;

void add(int u, int v, int cap){
    e[cc]=(edge){u, v, cap, 0, h[u]};
    h[u]=cc++;
    e[cc]=(edge){v, u, 0, 0, h[v]};
    h[v]=cc++;
}

int p[MAXN], num[MAXN], cur[MAXN], vis[MAXN];
int d[MAXN];
void rbfs(cint t){
    queue<int> q;   q.push(t);
    memset(vis, 0, sizeof(vis));
    d[t]=0;     vis[t]=1;
    while(!q.empty()){
        int u=q.front();    q.pop();
        for(int i=h[u]; i!=-1; i=e[i].nxt){
            i^=1;
            int v=e[i].u, cap=e[i].cap, ef=e[i].flow;
            if(!vis[v] && cap>ef){
                vis[v]=1;
                d[v]=d[u]+1;
                q.push(v);
            }
            i^=1;
        }
    }
}

int Augment(cint s, cint t){
    int a=INF, u;
    for(u=t; u!=s; u=e[p[u]].u)
        a=MIN(a, e[p[u]].cap-e[p[u]].flow);
    for(u=t; u!=s; u=e[p[u]].u){
        int i=p[u];
        e[i].flow+=a;
        e[i^1].flow-=a;
    }
    return a;
}

int isap(cint s, cint t, cint n){
    int i, flow=0;
    rbfs(t);
    memset(num, 0, sizeof(num));
    for(i=0; i<n; i++) num[d[i]]++;
    for(i=0; i<n; i++) cur[i]=h[i];
    for(int u=s; d[s]<n; ){
        if(u==t){
            flow+=Augment(s, t);
            u=s;
        }
        bool ok=false;
        for(i=cur[u]; i!=-1; i=e[i].nxt){
            int v=e[i].v, cap=e[i].cap, ef=e[i].flow;
            if(d[v]+1==d[u] && cap>ef){
                ok=true;
                p[v]=i;
                cur[u]=i;
                u=v;
                break;
            }
        }
        if(!ok){
            int tmp=n-1;
            for(i=h[u]; i!=-1; i=e[i].nxt){
                int v=e[i].v, cap=e[i].cap, ef=e[i].flow;
                if(cap>ef) tmp=MIN(tmp, d[v]);
            }
            if(--num[d[u]]==0) break;
            num[d[u]=tmp+1]++;
            cur[u]=h[u];
            if(u!=s) u=e[p[u]].u;
        }
    }
    return flow;
}

int cover_times[MAXK];
int can_drink[MAX_INTERVAL];
vector<int> drink[MAX_MONKEY];

int print(cint n, cint m, cint cnt){
    int i, j;
    memset(cover_times, 0, sizeof(cover_times));    //cover_times[i]为区间[i, i+1)的覆盖次数,即这个时段有多少monkey喝水
    for(i=1; i<=cnt; i++) can_drink[i]=rcontract[i]; //初始时没有monkey喝水
    for(i=0; i<n; i++){
        int prer=-1;
        vector<int> lft, rit;
        for(j=0; j<drink[i].size(); j++){
            int drinked = e[drink[i][j]].flow, u=e[drink[i][j]].u-n;
            int l=can_drink[u]/*, r=rcontract[u+1]*/;
            if(!drinked) continue;
            cint ansl=l, ansr=l+drinked;

            while(drinked--) cover_times[l++]++;
            while(cover_times[can_drink[u]]>=m) can_drink[u]++;

            if(ansl==prer) rit[rit.size()-1]=ansr;
            else{
                lft.push_back(ansl);
                rit.push_back(ansr);
            }
            prer=ansr;
        }
        printf("%d", lft.size());
        for(j=0; j<lft.size(); j++)
            printf(" (%d,%d)", lft[j], rit[j]);
        printf("\n");
    }
    return 0;
}

int main(){
//    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
    int kase=1, cnt, n, m;
    while(scanf(" %d", &n)==1 && n){
        int i, v, a, b, need_water=0;
        scanf(" %d", &m);
        memset(contract, 0, sizeof(contract));
        for(i=0; i<n; i++){
            scanf(" %d %d %d", &v, &a, &b);
            monkey[i]=(MON){v, a, b};
            need_water+=v;
            contract[a]=contract[b]=1;                      //  a==b  ?
        }
        for(cnt=i=0; i<MAXK; i++) if(contract[i]){
            contract[i]=++cnt;
            rcontract[cnt]=i;
        }

        memset(h, -1, sizeof(h));       cc=0;
        for(i=1; i<cnt; i++)
            add(0, i+n, m*(rcontract[i+1] - rcontract[i]));
        for(i=0; i<n; i++){
            int v=monkey[i].v, a=contract[monkey[i].a], b=contract[monkey[i].b];
            drink[i].clear();
            if(!v) continue;
            for(int j=a; j<b; j++){
                drink[i].push_back(cc);
                add(j+n, i+1, rcontract[j+1] - rcontract[j]);
            }
            add(i+1, n+cnt+1, v);
        }
        if(isap(0, n+cnt+1, n+cnt+2)<need_water) printf("Case %d: No\n", kase++);
        else printf("Case %d: Yes\n", kase++), print(n, m, cnt);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ramanujan/p/3354827.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值