UVA11167 Monkeys in the Emei Mountain

输入格式

输出格式

输入输出样例

输入 #1复制

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

输出 #1复制

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)

除了附加源点和汇点之外,1到N点为N个猴子,其余编号为N+i的点代表区间[i,i+1]

对每个猴子,向区间[a,b]中的每个子区间连边,容量为1,表示该猴子在这个时间段喝水,并从源点向该猴子连边,容量为v,表示该猴子一共需要喝v单位水,这样进入每个猴子的流量为v,一共会流向v个小区间

对每个子区间[i,i+1],向汇点连边,容量为m,这限制了该时间段喝水的猴子数,因为最多只能有m个猴子在此时喝水,所以从该区间流出的流向也不能大于m

求最大流,如果最大流恰好等于每个猴子的需求量的总和,那么所有猴子都喝到了足够的水,否则一定有猴子没有被满足

输出方案时,我将每个猴子喝水的时间段存起来,然后统计连续的区间并输出

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
struct edge
{
    int to,cap,flow;
};
vector<edge>e;
vector<int>v[50110];
vector<int>drink[110];
vector<pair<int,int> >ans[110];
int n,m,sum;
int s,t,maxflow,d[50110],kase,cnt;
int cur[50010];
bool vis[50110],use[50010];
void read(int& x)
{
    char c=getchar();
    x=0;
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')
    {
        x=x*10+c-'0';
        c=getchar();
    }
}
void link(int from,int to,int cap)
{
    e.push_back((edge){to,cap,0});
    e.push_back((edge){from,0,0});
    cnt=e.size();
    v[from].push_back(cnt-2);
    v[to].push_back(cnt-1);
}
bool bfs()
{
    queue<int>q;
    memset(vis,0,sizeof(vis));
    memset(d,INF,sizeof(d));
    q.push(s);
    d[s]=0;
    vis[s]=1;
    while(!q.empty())
    {
        int fa=q.front();
        q.pop();
        for(int i=0;i<v[fa].size();i++)
        {
            edge& ed=e[v[fa][i]];
            if(!vis[ed.to]&&ed.cap>ed.flow)
            {
                d[ed.to]=d[fa]+1;
                vis[ed.to]=1;
                q.push(ed.to);
            }
        }
    }
    return vis[t];
}
int dfs(int x,int a)
{
    if(x==t||a==0)return a;
    int flow=0,f;
    for(int& i=cur[x];i<v[x].size();i++)
    {
        edge& ed=e[v[x][i]];
        if(d[ed.to]==d[x]+1&&(f=dfs(ed.to,min(a,ed.cap-ed.flow)))>0)
        {
            flow+=f;
            ed.flow+=f;
            e[v[x][i]^1].flow-=f;
            a-=f;
            if(a==0)break;
        }
    }
    return flow;
}
int main()
{
    while(1)
    {
        read(n);
        if(!n)return 0;
        read(m);
        memset(use,0,sizeof(use));
        maxflow=0;sum=0;
        s=0;
        t=n+50001;
        v[s].clear();
        v[t].clear();
        e.clear();
        for(int i=1;i<=n;i++)
        {
            int a,b,c;
            read(a);
            read(b);
            read(c);
            sum+=a;
            v[i].clear();
            link(s,i,a);
            for(int j=b;j<c;j++)
            {
                if(!use[j])
                {
                	v[n+j].clear();
                    link(n+j,t,m);
                    use[j]=1;
                }
                link(i,n+j,1);
            }
        }
        while(bfs())
        {
            memset(cur,0,sizeof(cur));
            maxflow+=dfs(s,INF);
        }
        printf("Case %d: ",++kase);
        if(maxflow<sum)
        {
            printf("No\n");
            continue;
        }
        else printf("Yes\n");
        for(int i=1;i<=n;i++)
        {
        	drink[i].clear();
            for(int j=0;j<v[i].size();j++)
            {
                edge ed=e[v[i][j]];
                if(ed.cap==ed.flow&&ed.to!=s)drink[i].push_back(ed.to);
            }
        }
        for(int i=1;i<=n;i++)
        {
        	ans[i].clear();
            int times=0,pos=drink[i][0];
            sort(drink[i].begin(),drink[i].end());
            drink[i].push_back(INF);
            for(int j=0;j<drink[i].size();j++)
            {
                if(drink[i][j]+1!=drink[i][j+1])
                {
                    ans[i].push_back(make_pair(pos,drink[i][j]+1));
                    pos=drink[i][j+1];
                    times++;
                }
            }
            printf("%d",--times);
            for(int j=0;j<ans[i].size()-1;j++)
            {
                printf(" (%d,%d)",ans[i][j].first-n,ans[i][j].second-n);
            }
            putchar('\n');
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值