HDU3572最大流判满流--isap

/*************************************************************************
* author:crazy_石头
* algorithm:sap+当前弧+gap优化
* date:2013/09/29
* problem:HDU3572网络流
* 分析:把每个任务看成一个点,s到每个任务连边,容量为任务需要运行的天数。
* 把每天看成一个点,每天向t连边,容量为m,表示一天最多运行m个任务。
* 每个任务都向s-e天连边,容量为1,表示这个任务可以在这些天运行。
* 最后判断最大流是否等于所有任务需要运行的天数总和即可。
**************************************************************************/
#include<cstdio>
#include<cstring>
#include<climits>

using namespace std;

#define N 90005
#define M 4000005
#define INF INT_MAX

const int maxn=500;

int source,sink,nodenum;
int num,pre[N],dis[N],gap[N],head[N],cur[N];

struct node
{
    int u,v,w;
    int next;
}e[M];

inline void add(int u,int v,int w)
{
     e[num].u=u;
     e[num].v=v;
     e[num].w=w;
     e[num].next=head[u];
     head[u]=num++;
}

inline void addedge(int u,int v,int w)
{
     add(u,v,w);
     add(v,u,0);
}

inline int max(int a,int b)
{
    return a>b?a:b;
}

inline int min(int a,int b)
{
    return a<b?a:b;
}

inline int isap(int s,int t,int n)
{
     int top,mindis,maxflow=0,v,i,aug;
     bool flag;
     for(i=0;i<=n;i++)
     {
         cur[i]=head[i];
         gap[i]=dis[i]=0;
     }
     top=pre[s]=s;
     aug=INF;

     while(dis[s]<n)
     {
         flag=0;
         for(i=cur[top];i!=-1;i=e[i].next)
         {
             v=e[i].v;
             if(e[i].w>0&&dis[top]==dis[v]+1)
             {
                 flag=1;
                break;
             }
         }
         if(flag)
         {
             pre[v]=top;
             cur[top]=i;
             aug=min(aug,e[i].w);
             top=v;
             if(top==t)
             {
                 while(top!=s)
                 {
                     top=pre[top];
                     e[cur[top]].w-=aug;
                     e[cur[top]^1].w+=aug;
                 }
                 top=s;
                 maxflow+=aug;
                 aug=INF;
             }
         }
         else
         {
             if(--gap[dis[top]]==0)
                break;
             mindis=n;
             cur[top]=head[top];
             for(i=head[top];i!=-1;i=e[i].next)
             {
                 v=e[i].v;
                 if(e[i].w>0&&dis[v]+1<mindis)
                 {
                     mindis=dis[v]+1;
                     cur[top]=i;
                 }
             }
             dis[top]=mindis;
             gap[mindis]++;
             if(top!=s)
                 top=pre[top];
         }
     }
     return maxflow;
}

inline void init()
{
     num=0;
     memset(head,-1,sizeof(head));
}

int main()
{
     int test,n,m;
     scanf("%d",&test);
     for(int ii=1;ii<=test;ii++)
     {
         scanf("%d%d",&n,&m);
         init();
         source=0,sink=n+500+1,nodenum=n+2+500;
         int tot=0;
         for(int i=1;i<=n;i++)
         {
             int p,s,e;
             scanf("%d%d%d",&p,&s,&e);
             tot+=p;
             addedge(source,i,p);
             for(int j=s;j<=e;j++)
             {
                 addedge(i,n+j,1);
             }
         }

         for(int i=1;i<=500;i++)
         {
             addedge(i+n,sink,m);
         }

         if(tot==isap(source,sink,nodenum))
                 printf("Case %d: Yes\n",ii);
         else
                 printf("Case %d: No\n",ii);
         printf("\n");
     }
     return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值