码迷,mamicode.com
首页 > 编程语言 > 详细

HDU ACM 3572 Task Schedule 网络最大流->dinic算法

时间:2015-05-19 16:36:17      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   网络流   

分析:

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

标签:c   c++   acm   算法   网络流   

原文地址:http://blog.csdn.net/a809146548/article/details/45845257

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!