【最大流】【HDU3572】Task Schedule
题意:
有N个事件,M台机器。事件有开始时间,持续时间,要在结束时间之前完成,问是否能完成所有事件?
非自己思考出来的
建图:把每个任务和每一天都看做一个点,添加源点和汇点。源点与每个任务之间连一条边,容量为完成该任务所需处理次数。若第i个任务可以在Si至Ei天处理,则由该任务向这些天分别连一条边,容量为1,表示此任务每天只能被处理一次。最后,从每一天连一条到汇点的边,容量为机器数M,表示每天可以处理M个任务。若求出的最大流等于所有任务需要处理的次数之和,说明能完成任务;否则,不能完成任务。
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 using namespace std; int N,M; using namespace std; const int MAXN=5000+5; const int MAXM=300000+5; const int INF=0x3f3f3f3f; const int TT=500+500+2; const int S=0; struct Edge { int to,next,cap,flow; void get(int a,int b,int c,int d) { to=a;next=b;cap=c;flow=d; } }edge[MAXM]; int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN]; void init() { tol=0; memset(head,-1,sizeof(head)); } //单向图三个参数,无向图四个参数 void addedge(int u,int v,int w,int rw=0) { edge[tol].get(v,head[u],w,0);head[u]=tol++; edge[tol].get(u,head[v],rw,0);head[v]=tol++; } int sap(int start,int end,int N) { memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u=start; pre[u]=-1; gap[0]=N; int ans=0; while(dep[start]<N) { if(u==end) { int Min=INF; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; } u = start; ans+=Min; continue; } bool flag=false; int v; for(int i=cur[u];i !=-1;i=edge[i].next) { v=edge[i].to; if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) { flag=true; cur[u]=pre[v]=i; break; } } if(flag) { u=v; continue; } int Min=N; for(int i=head[u];i!=-1;i=edge[i].next) if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min) { Min=dep[edge[i].to]; cur[u]=i; } gap[dep[u]]--; if(!gap[dep[u]]) return ans; dep[u]=Min+1; gap[dep[u]]++; if(u!=start) u=edge[pre[u]^1].to; } return ans; } void File() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); } int sum; void input() { sum=0; int p,s,e; cin>>N>>M; for(int i=1;i<=N;i++) { scanf("%d%d%d",&p,&s,&e); sum+=p; addedge(S,i,p); //源点到任务连一条流量为p的边 for(int j=s;j<=e;j++) { addedge(i,N+j,1); //任务到s-e间连一条流量为1的边 } } for(int i=1;i<=500;i++) { addedge(N+i,TT,M); //时间到汇点连一条流量为M的边,表示一天最多处理的事情 } } int main() { // File(); int T; cin>>T; int CASE=0; while(T--) { printf("Case %d: ",++CASE); init(); input(); if(sum==sap(S,TT,1003)) cout<<"Yes"<<endl; else cout<<"No"<<endl; cout<<endl; } }