hdu2883

这道题目比前面一道求满流的题目多了一点不一样,我理解就是离散化,因为si,ei的范围实在太大,但n的范围却不大,则

把所有si,ei列出来,排序,得到最多2*n-1个区间,则每个区间就是各节点,到汇点的容量限制就是m*区间长度。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=1<<30;
int si[210],ei[210],ni[210],ti[210],head[2100],h[2100],num[4200];
int a[410],n,m,sum;
int cnt,ans,c;
struct edge
{
       int x,y,flow,nxt,op;
}em[1000010];
void add(int x,int y,int c)
{
     em[++cnt].x=x;
     em[cnt].y=y;
     em[cnt].flow=c;
     em[cnt].nxt=head[x];
     head[x]=cnt;
     em[cnt].op=cnt+1;
     cnt++;
     em[cnt].x=y;
     em[cnt].y=x;
     em[cnt].flow=0;
     em[cnt].nxt=head[y];
     head[y]=cnt;
     em[cnt].op=cnt-1;
}
int dfs(int x,int flow)
{
    if(x==n+c)
    return flow;
    int temp=flow,pos=n+c+1;
    for(int j=head[x];j;j=em[j].nxt)
    {
            int y=em[j].y;
            int w=em[j].flow;
            if(h[x]==h[y]+1&&w>0)
            {
                                 int temp_flow=dfs(y,min(temp,w));
                                 temp-=temp_flow;
                                 em[j].flow-=temp_flow;
                                 em[em[j].op].flow+=temp_flow;
                                 if(!temp||h[0]==n+c+1)
                                 return flow-temp;
            }
            if(w>0&&h[y]<pos)
            pos=h[y];
    }
    if(temp==flow)
    {
                  num[h[x]]--;
                  if(num[h[x]]==0)
                  h[0]=n+c+1;
                  else
                  {
                      h[x]=pos+1;
                      num[h[x]]++;
                  }
    }
    return flow-temp;
}
void isap()
{
     memset(h,0,sizeof(h));
     memset(num,0,sizeof(num));
     while(h[0]<n+c+1)
     {
                    ans+=dfs(0,INF);
     }
 //    printf("%d %d\n",sum,ans);
     if(ans==sum)
     printf("Yes\n");
     else
     printf("No\n");
}
int main()
{
    while(2==scanf("%d%d",&n,&m))
    {
                                 sum=0;
                                 int tot=0;
                                 cnt=0;
                                 memset(head,0,sizeof(head));
                                 for(int i=1;i<=n;i++)
                                 {
                                         scanf("%d%d%d%d",si+i,ni+i,ei+i,ti+i);                                         
                                         a[++tot]=si[i];
                                         a[++tot]=ei[i];
                                         add(0,i,ni[i]*ti[i]);
                                         sum+=ni[i]*ti[i];
                                 }
                                 sort(a+1,a+tot+1);
                                 c=0;
                                 for(int i=1;i<=tot;i++)
                                 if(a[c]!=a[i])
                                 a[++c]=a[i];
                               /*  for(int i=1;i<=c;i++)
                                 printf("%d\n",a[i]);*/
                                 for(int i=1;i<=c-1;i++)
                                 {
                                         int num=(a[i+1]-a[i])*m;
                                         add(n+i,n+c,num);
                                 }
                                 for(int i=1;i<=c-1;i++)
                                 {
                                         for(int j=1;j<=n;j++)
                                         if(si[j]<=a[i]&a[i+1]<=ei[j])
                                         add(j,i+n,INF);
                                 } 
                                 ans=0;
                                 isap();
    }    
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值