POJ 1698 Alice's Chance

/* 一个演员很想参加film,但是一天只能参加一项,且每项必须在规定的几个星期内参加规定的天数,求演员是否能全部完成所有的film档期。 可以考虑用网络流做,加源汇点,如果film_i 和week_i_day_j天有联系,那么就连一条INF边,源点到film_i连一条day_i边,各个星期的天数到汇点连一条1边,求最大流是否和总天数相等。最大流用isap就可以了,非常快。 */

#include <iostream>
#include 
<cstdio>
#include 
<algorithm>
#include 
<memory.h>
#include 
<queue>
using namespace std;

#define INF 0x7ffffff
#define MAXN 500
#define MAXE 20000

struct Edge{
    
int next,pair;
    
int v,cap,flow;
}edge[MAXE];
int net[MAXN];
int nv,ne,s,t,index,max_week,sum;
void init()
{
    index 
= 0;
    memset(net,
-1,sizeof(net));
    s 
= 0// start position
    max_week = -1;
    sum 
= 0;
}
void add_edge(const int& u,const int& v,const int& val)
{
    edge[index].next 
= net[u];
    net[u] 
= index;
    edge[index].v 
= v;
    edge[index].cap 
= val;
    edge[index].flow 
= 0;
    edge[index].pair 
= index + 1;
    
++index;
    edge[index].next 
= net[v];
    net[v] 
= index;
    edge[index].v 
= u;
    edge[index].cap 
= 0;
    edge[index].flow 
= 0;
    edge[index].pair 
= index - 1;
    
++index;
}
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));
    
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+1;
            
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;
        }
        
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;
}

int main()
{
    
int i,j,k,h,time,ans,n,work[7],day,week;
    scanf(
"%d",&time);
    
while(time--)
    {
        init();
        scanf(
"%d",&n);
        
for(i = 1; i <= n; ++i)
        {
            
for(j = 0;j < 7++j)
                scanf(
"%d",&work[j]);
            scanf(
"%d%d",&day,&week);
            add_edge(s,i,day);
            
for(j = 0;j < week; ++j)
                
for(k = 0;k < 7++k)
                    
if(work[k]) // can do 
                        add_edge(i,n+j*7+k+1,INF);
            max_week 
= max_week>week?max_week:week;
            sum 
+= day;
        }
        t 
= n+max_week*7+1;
        nv 
= t + 1;
        
for(i = 0;i < max_week; ++i )
            
for(j = 1;j <= 7++j)
                add_edge(n
+i*7+j,t,1);
        ans 
= ISAP();
        
if(sum == ans)
            printf(
"Yes\n");
        
else
            printf(
"No\n");
    }
    
return 0;
}

 

原文地址:https://www.cnblogs.com/lvpengms/p/1662746.html