Hdu 2883 最大流 区间 判满流

题意:给定n个顾客,第i号顾客在si到达,点了ni个羊肉串,每个羊肉串需要ti个时间烤好。顾客想要在ei得到,一个烤炉只烤m串。

这题有点像hdu的3572 但是那是以点位状态考虑的,因为羊肉串只要在规定时间内烤完就可以了所以在考虑时间的时候将时间转换为时间区间 并建点 3572的题解中有图解见:http://blog.csdn.net/luyuncheng/article/details/7944417但是完成时间又会有重复区间所以需要排序后去除重复区间

将所有的到达时间和结束时间按升序排序,得到 x <= 2n-1 个时间区间。建立网络流模型:s为源,t为汇,每个顾客i作为一个结点并连边(s, i, ni*ti),每个区间j作为一个结点并连边(j, t, (ej-sj)*M),其中sj, ej分别表示区间j的起始时间和终止时间。对任意顾客i和区间j,若 [sj, ej] 完全包含在 [si, ei] 之中,则连边(i, j, INF)。若最大流等于 ∑ni*ti 则是 Yes,否则是 No。

这样转化后就和那到题目是一样的了

 

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring> 
using namespace std;   
#define MAXN 500 
#define MAXE 500002 
#define INF 0x7ffffff      
int ne,nv,tmp,s,t,index;  
struct Edge{ 
    int next,pair; 
    int v,cap,fLow; 
}edge[MAXE];
int net[MAXN];
int ISAP() 
{ 
	int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN]; 
 
    int cur_fLow,max_fLow,u,tmp,neck,i; 
    memset(dist,0,sizeof(dist)); 
    memset(numb,0,sizeof(numb)); 
    memset(pre,-1,sizeof(pre)); 
    for(i = 1 ; i <= nv ; ++i) 
        curedge[i] = net[i]; 
    numb[nv] = nv; 
    max_fLow = 0; 
    u = s; 
    while(dist[s] < nv) 
    { 
        if(u == t) 
        { 
            cur_fLow = INF; 
            for(i = s; i != t;i = edge[curedge[i]].v)  
            {   
                if(cur_fLow > edge[curedge[i]].cap) 
                { 
                    neck = i; 
                    cur_fLow = edge[curedge[i]].cap; 
                } 
            } 
            for(i = s; i != t; i = edge[curedge[i]].v) 
            { 
                tmp = curedge[i]; 
                edge[tmp].cap -= cur_fLow; 
                edge[tmp].fLow += cur_fLow; 
                tmp = edge[tmp].pair; 
                edge[tmp].cap += cur_fLow; 
                edge[tmp].fLow -= cur_fLow; 
            } 
            max_fLow += cur_fLow; 
            u = neck; 
        } 
        /* if .... eLse ... */
        for(i = curedge[u]; i != -1; i = edge[i].next) 
            if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1) 
                break; 
        if(i != -1) 
        { 
            curedge[u] = i; 
            pre[edge[i].v] = u; 
            u = edge[i].v; 
        }else{ 
            if(0 == --numb[dist[u]]) break; 
            curedge[u] = net[u]; 
            for(tmp = nv,i = net[u]; i != -1; i = edge[i].next) 
                if(edge[i].cap > 0) 
                    tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v]; 
            dist[u] = tmp + 1; 
            ++numb[dist[u]]; 
            if(u != s) u = pre[u]; 
        } 
    }      
    return max_fLow; 
}
void addedge(int u,int v,int f)
{
	edge[index].next = net[u]; 
    edge[index].v = v; 
    edge[index].cap = f; 
    edge[index].fLow = 0; 
    edge[index].pair = index+1; 
    net[u] = index++; 
    edge[index].next = net[v]; 
    edge[index].v = u; 
    edge[index].cap = 0; 
    edge[index].fLow = 0; 
    edge[index].pair = index-1; 
    net[v] = index++;
	
} 
int main() 
{ 
    int i,j,np,nc,m,n; 
    int a,b,d,k,vaL;
	int se[MAXN],e[MAXN],tol[MAXN*2];
	while(scanf("%d%d",&n,&m)!=EOF)
	{ 
		int sum=0,tot=0;
		index=0;//index从0开始扫 
        s = 0; 
        t = 0;
		int contime=0; 
		memset(se,0,sizeof(se));
		memset(e,0,sizeof(e));
		memset(tol,0,sizeof(tol));
        memset(net,-1,sizeof(net));        
		for(i=1;i<=n;i++)
		{
			int pi,si,ei,ni,ti;
			scanf("%d%d%d%d",&se[i],&ni,&e[i],&ti);
			pi=ni*ti;
			sum+=pi;
			addedge(s,i,pi);
			tol[tot++]=se[i];
			tol[tot++]=e[i];	 
		}
		sort(tol,tol+tot);
		int c=0;
		for(i=1,c=0;i<tot;++i)
			if(tol[c]!=tol[i])tol[++c]=tol[i];
		t=c+n+1;
		nv=t+1;
		for(i=1;i<=c;i++)
		{
			int temp=tol[i]-tol[i-1];
			addedge(i+n,t,temp*m);
			for(j=1;j<=n;j++)
			{
				if(tol[i-1]>=se[j]&&tol[i]<=e[j])  
                {  
                    addedge(j,i+n,INF);  
                }  

			}		
			
		}
		int ans=ISAP();
		if (ans  == sum)  
            printf("Yes\n");  
        else printf("No\n");  

    } 
    return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值