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

分析:

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

HDU ACM 3572 Task Schedule 网络最大流->dinic算法的相关文章

HDU 3572 Task Schedule(最大流Dinic算法)

该题非常经典,建图的方法非常巧妙,因为每个任务的完成不一定要连续,而且可以换机器完成,而且我们注意到时间点最多500,很小,所以我们将时间点抽出来建图. 对于每个任务,将其时间范围内的点与之连起来,容量显然为1 ,并与汇点相连,容量为p[i] .  对于每个时间点,因为最多可以有m台机器同时工作,所以容量为m . 一开始老想着任务和机器之间怎么建立联系了. 推荐题目: 点击打开链接 细节参见代码: #include<bits/stdc++.h> using namespace std; typ

网络最大流 dinic算法

一句话题意:给出一个网络图,以及其源点和汇点,求出其网络最大流 //dinic算法; //时间复杂度O(V^2E); #include<bits/stdc++.h> #define inf 999999 #define maxn 200000 using namespace std; int n,m,s,t; int ans=0; struct Edge { int to,next,w; }; struct Edge edge[maxn]; int head[maxn],val[maxn],p

hdu 3572 Task Schedule(最大流)

hdu 3572 Task Schedule Description Our geometry princess XMM has stoped her study in computational geometry to concentrate on her newly opened factory. Her factory has introduced M new machines in order to process the coming N tasks. For the i-th tas

hdoj 3572 Task Schedule【最大流】

题目:hdoj 3572 Task Schedule 题意:有m台机器和n个任务,然后给出每个任务的开始时间和结束时间以及需要的天数,让你判断有没有这样条件的安排 分析:网络流题目,比较难想到的是把时间区间怎么在图里面建,其实是在这个区间的每个点都连一条边,建图方案. 超级源点s到每个任务 i 连边,容量为第 i 个任务需要的天数,然后每个任务向满足要求的日期连一条容量为1的边,即从开始到结束都连,然后所有日期到汇点连容量m的边,因为每个机器最多同时能够做m个task. 这样建图发现图中的点最多

【HDU】 3572 Task Schedule

Task Schedule 题目链接 Task Schedule 题目大意 总共有m个机器,n个任务,每个任务具有Si,Ei,Pi,三种属性,从Si到Ei,总共需要Pi天去完成,每个机器同一时间只能运行一个任务,任务运行时可以被中断去完成其他任务.现在问是否有一种调度方法,使这n个任务能全部完成. 题解 这一题是网络流的题目,难点在于如何建图. 因为每个任务都可以在Si到Ei内任何一个时间运行,我们想到从每个任务向这些可行的时间点建边,又因为每个任务需要运行Pi天,所以我们建立一个源点,向每个任

HDU 3572 Task Schedule(最大流判断满流)

https://vjudge.net/problem/HDU-3572 题意: 有N个作业和M台机器,每个作业都有一个持续时间P,工作的日期为S~E.作业可以断断续续的在不同机器上做,每台机器每次只可以处理一个作业.判断是否可以在作业的工作日期内完成所有作业. 思路: 建立源点0和汇点t,因为天数最多为500,所有我们将日期的编号定为1~500,作业的编号为500+i. 对于每个作业,与源点0相连,容量为P,意味着它必须走完这P容量才能完成这作业.与S~E相连,容量为1.日期与汇点相连,容量为m

hdu 3572 Task Schedule【 最大流 】

求出最大流,再判断是否满流 先不理解为什么要这样建图 后来看了这一篇题解 http://blog.csdn.net/u012350533/article/details/12361003 把0看做源点st 把每一个任务看做一个点 st到每个任务连边,容量为p,表示任务完成需要的天数 每个任务到每个任务的开始至结束时间连边,容量为1,表示这个任务可以在这些天完成 每一天向汇点ed连边,容量为m,表示一天最多运行m个任务 然后判断最大流是否等于执行完所有任务所需要的时间 1 #include<cst

HDU - 3572 Task Schedule (最大流)

题目大意:有N个任务,M台机器. 每个任务有相应的起始时间,截至时间和完成时间 每台机器一小时可以做1个单位的工作量,每个任务的完成可以不连续,但每次只能由一台机器完成 问能否完成所有任务 解题思路:因为只有500分钟,所以可以将每分钟都设成1条边,连向超级汇点,容量为M 每个任务连接向超级源点,容量为完成时间 接着将任务连接像时间(分钟),连接的条件为,该时间在起始时间和截止时间这个区间之内 这样图就构成了 #include <cstdio> #include <cstring>

HDU 3572 Task Schedule(ISAP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3572 题意:m台机器,需要做n个任务.第i个任务,你需要使用机器Pi天,且这个任务要在[Si  ,  Ei]区间内完成才有效.对于一个任务,只能由一个机器来完成,一个机器同一时间只能做一个任务.当然,一个任务可以分成几段不连续的时间来完成.问,能否做完全部任务. 题意很清晰,也就是判断是否是满流. 对于网络流问题,模板大家都有,关键在于如何建图(详见资料) 思路:今天问了龙哥,对建图有了一定的了解,