分析:
建图:每个任务和每一天分别看做一个点,添加源和汇点。源点和每个任务连一条边,每天边的容量为完成对应任务所需处理次数。若第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