分析:
建图:每个任务和每一天分别看做一个点,添加源和汇点。源点和每个任务连一条边,每天边的容量为完成对应任务所需处理次数。若第i个任务能够在Si至Ei天处理,则由该任务向这些天分别连一条边,容量为1,表示此任务每天只能被处理一次。最后,每一天分别连一条边到汇点,容量为机器数M,即每天可以处理M个任务。若求出的最大流等于所有任务需要处理的次数之和,说明能完成任务;否则,不能。
#include<iostream> #include<vector> #include<queue> using namespace std; #define N 1111 #define INF 0x7fffffff #define min(a,b) ((a)<(b)?(a):(b)) class Max_Flow //DINIC算法 { private: struct EDGE { EDGE(int _from,int _to,int _cap,int _flow) { from=_from; to=_to; cap=_cap; flow=_flow; } int from,to,cap,flow; }; public: Max_Flow(){ m_iM=0;} ~Max_Flow(){} void AddEdge(int _from,int _to,int _cap); //_cap表示容量 int MaxFlow(int s,int t); private: bool BFS(); //BFS建立分层图 int DFS(int x,int a); //DFS进行多路增广 int m_iM,m_iS,m_iT; //边数(包括反向边),源点,汇点 vector<EDGE> m_vEdges; //边表m_edges[e]和m_edges[e^1]互为反向弧 vector<int> m_vG[N]; //领接表 bool m_bVis[N]; //BFS使用的访问数组 int m_iD[N]; //从源点到点i的距离 int m_iCur[N]; //表示当前弧的下标 }; int Max_Flow::MaxFlow(int s,int t) { int flow=0; this->m_iS=s; this->m_iT=t; while(BFS()) { memset(m_iCur,0,sizeof(m_iCur)); flow+=DFS(s,INF); } return flow; } int Max_Flow::DFS(int x,int a) { int _flow,f; if(x==m_iT || a==0) return a; _flow=0; int& i=m_iCur[x]; //从上次弧考虑,避免不必要的重复搜索 for(;i<m_vG[x].size();i++) { EDGE& e=m_vEdges[m_vG[x][i]]; if(m_iD[x]+1==m_iD[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0) { e.flow+=f; m_vEdges[m_vG[x][i]^1].flow-=f; //反向边 _flow+=f; a-=f; if(a==0) break; } } return _flow; } bool Max_Flow::BFS() { memset(m_bVis,0,sizeof(m_bVis)); queue<int> q; int x,i; q.push(m_iS); m_iD[m_iS]=0; m_bVis[m_iS]=1; while(!q.empty()) { x=q.front(); q.pop(); for(i=0;i<m_vG[x].size();i++) { EDGE& e=m_vEdges[m_vG[x][i]]; if(!m_bVis[e.to] && e.cap>e.flow) //只需要考虑残量网络中的弧 { m_bVis[e.to]=1; m_iD[e.to]=m_iD[x]+1; q.push(e.to); } } } return m_bVis[m_iT]; } void Max_Flow::AddEdge(int _from,int _to,int _cap) { m_vEdges.push_back(EDGE(_from,_to,_cap,0)); m_vEdges.push_back(EDGE(_to,_from,0,0)); m_iM+=2; m_vG[_from].push_back(m_iM-2); m_vG[_to].push_back(m_iM-1); } int main() { int T,n,M,Pi,Si,Ei,c,i,j,sum,maxday; int s,t; ios::sync_with_stdio(false); cin>>T; c=0; while(T--) { cin>>n>>M; Max_Flow max_flow; sum=0; maxday=-1; s=0; for(i=1;i<=n;i++) { cin>>Pi>>Si>>Ei; sum+=Pi; maxday=maxday>Ei?maxday:Ei; max_flow.AddEdge(s,i,Pi); //源点和第i个任务建边,容量为完成任务天数 for(j=Si;j<=Ei;++j) max_flow.AddEdge(i,n+j,1);//任务和第j天建边,容量为1 } t=n+maxday+1; for(i=1;i<=maxday;i++) max_flow.AddEdge(n+i,t,M); //天数和汇点建边,表示每天有m台机器 if(sum==max_flow.MaxFlow(s,t)) //若最大流等于需要天数之和则可以完成 cout<<"Case "<<++c<<": Yes"<<endl; else cout<<"Case "<<++c<<": No"<<endl; cout<<endl; } return 0; }
HDU ACM 3572 Task Schedule 网络最大流->dinic算法
原文地址:http://blog.csdn.net/a809146548/article/details/45845257