hdu 3572 Task Schedule 最大流+建图+dinic入门

题目:

Task Schedule

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7665    Accepted Submission(s): 2356


Problem 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 task, the factory has to start processing it at or after day Si, process it for Pi days, and finish the task before or at day Ei. A machine can only work on one task at a time, and each task can be processed by at most one machine at a time. However, a task can be interrupted and processed on different machines on different days. 
Now she wonders whether he has a feasible schedule to finish all the tasks in time. She turns to you for help.
 

Input
On the first line comes an integer T(T<=20), indicating the number of test cases.

You are given two integer N(N<=500) and M(M<=200) on the first line of each test case. Then on each of next N lines are three integers Pi, Si and Ei (1<=Pi, Si, Ei<=500), which have the meaning described in the description. It is guaranteed that in a feasible schedule every task that can be finished will be done before or at its end day.
 

Output
For each test case, print “Case x: ” first, where x is the case number. If there exists a feasible schedule to finish all the tasks, print “Yes”, otherwise print “No”.

Print a blank line after each test case.
 

Sample Input
  
  
2 4 3 1 3 5 1 1 4 2 3 7 3 5 9 2 2 2 1 3 1 2 2
 

Sample Output
  
  
Case 1: Yes Case 2: Yes


分析:

n个任务,m台机器,每一个任务需要在si之后开始,在ei之前结束,需要pi的时间完成
难点在于建图,建图方法参考自:http://blog.csdn.net/ahfywff/article/details/7240087


把每个任务和每一天都看做一个点,添加超级源点和超级汇点。超级源点与每个任务之间连一条边,容量为完成该任务所需处理次数pi,表示每个任务需要占用pi的流量。若第i个任务可以在si至ei天处理,则由该任务向这些天分别连一条边,容量为1,表示此任务在这一天最多可以被处理1次。最后,从每一天连一条到汇点的边,容量为机器数m,表示每天最多可以处理m个任务。
若求出的最大流等于所有任务需要处理的次数之和,说明存在一个方案容许所有任务在要求的时间内完成;否则,不能完成任务。


代码:

1.fold TLE:

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>    //tower()
#include<set>
#include<map>
#include<string.h>
#include<iomanip>// cout<<setprecision(1)<<fixed<<a;
#include<vector>   
#include<time.h>  
#include<assert.h>  //assert
#include<math.h>	
#include<algorithm>
#include<bitset>
#include<limits.h>
#include<stack>
#include<queue>
using namespace std;
const int maxn=2000;
const int inf=INT_MAX;

struct edge{
	int to;//终点
	int cap;//容量
	int rev;//反向边
};

int t,n,m,day,cc,sum;

vector <edge> g[maxn];
bool used[maxn];

//向图中增加一条从s到t容量为cap的边 
void add_edge(int from,int to,int cap){
	g[from].push_back((edge){to,cap,g[to].size()});
	g[to].push_back((edge){from,0,g[from].size()-1});
}

//寻找增广路 
int dfs(int v,int t,int f){
	if(v==t) return f;
	used[v]=true;
	for(int i=0;i<g[v].size();++i){
		edge &e=g[v][i];
		if(!used[e.to]&&e.cap>0){
			int d=dfs(e.to,t,min(f,e.cap));
			if(d>0){
				e.cap-=d;
				g[e.to][e.rev].cap+=d;
				return d;
			}
		}
	}
	return 0;
}

int max_flow(int s,int t){
	int flow=0;
	for(;;){
		memset(used,0,sizeof(used));
		int f=dfs(s,t,inf);
		if(f==0) return flow;
		flow+=f;
	}
}

int main(){///
	int u,v,z;
	scanf("%d",&t);
	for(int cas=1;cas<=t;++cas){
		day=-1;sum=0;
		//建图 0 为源点,1-n为任务,n+1 -  n+day位为日期, n+1+day为汇点 
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d%d%d",&u,&v,&z);
			add_edge(0,i,u);
			for(int j=v;j<=z;++j){
				add_edge(i,n+j,1);//n+j not j...
			}
			day=max(day,z);
			sum+=u;
		}
		for(int i=1;i<=day;++i){
			add_edge(n+i,n+1+day,m);
		}
		cc=max_flow(0,n+1+day);
		if(cc==sum) printf("Case %d: Yes\n\n",cas);
		else printf("Case %d: No\n\n",cas);
		for(int i=0;i<=maxn;++i) g[i].clear();
	}
	return 0;
}


2.dinic AC:

#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>    //tower()
#include<set>
#include<map>
#include<string.h>
#include<iomanip>// cout<<setprecision(1)<<fixed<<a;
#include<vector>
#include<time.h>  
#include<assert.h>  //assert
#include<math.h>	
#include<algorithm>
#include<bitset>
#include<limits.h>
#include<stack>
#include<queue>
using namespace std;
const int maxn=2000;
const int inf=INT_MAX;

struct edge{
	int to;//终点
	int cap;//容量
	int rev;//反向边
};

int t,n,m,day,cc,sum;

vector<edge> g[maxn];
int level[maxn];//顶点到源点的距离标号 
int iter[maxn];//当前弧 在其之前的边已经没有用了 

//向图中增加一条从from到to容量为cap的边 
void add_edge(int from,int to,int cap){
    g[from].push_back((edge){to,cap,g[to].size()});
    g[to].push_back((edge){from,0,g[from].size() - 1});
}

//通过bfs记算从源点出发的距离标号 
void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int> que;
    level[s]=0;
    que.push(s);
    while(!que.empty()){
        int v=que.front(); que.pop();
        for(int i=0;i<g[v].size();i++){
            edge &e=g[v][i];
            if(e.cap>0&&level[e.to]<0){
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}

//通过dfs寻找增广路 
int dfs(int v,int t,int f){
    if(v==t) return f;
    for(int &i=iter[v];i<g[v].size();i++){
        edge &e=g[v][i];
        if(e.cap>0&&level[v]<level[e.to]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                g[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t){
    int flow = 0;
    for(;;){
        bfs(s);
        if(level[t]<0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,inf))>0){
            flow+=f;
        }
    }
}

int main(){///140MS	7956K
	int u,v,z;
	scanf("%d",&t);
	for(int cas=1;cas<=t;++cas){
		day=-1;sum=0;
		//建图 0 为源点,1-n为任务,n+1 -  n+day位为日期, n+1+day为汇点 
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d%d%d",&u,&v,&z);
			add_edge(0,i,u);
			for(int j=v;j<=z;++j){
				add_edge(i,n+j,1);//n+j not j...
			}
			day=max(day,z);
			sum+=u;
		}
		for(int i=1;i<=day;++i){
			add_edge(n+i,n+1+day,m);
		}
		cc=max_flow(0,n+1+day);
		if(cc==sum) printf("Case %d: Yes\n\n",cas);
		else printf("Case %d: No\n\n",cas);
		for(int i=0;i<=maxn;++i) g[i].clear();
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值