标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5031 Accepted Submission(s): 1642
2 4 3 1 3 5 1 1 4 2 3 7 3 5 9 2 2 2 1 3 1 2 2
Case 1: Yes Case 2: Yes
题意:给你m个机器和n个任务,每个机器一次只能运行一个任务,但是可以运行中断换任务,每个任务有一个开始的最早时间Si和完成的最晚时间Ei,这个任务完成需要的时间Pi,问是否可以完成所有任务。。
*****这个题比较难想到网络流,但是想到点上了就发现这就是个网络流,我开始用最初学的那个算法写,结果CE,不明就里,就改啊改的,然后是RE,说是下标越界,再改就成了TLE,超时。。。然后临时在网上复习了一下dinic算法,这个耗时小一些。。。
题解:和普通网络流一样,设置一个超级原点S和超级汇点T,S连接每个任务,流量限制为这个任务的Pi,T连接每个时间点,流量限制为m,因为同一时刻m个机器是能同时运行的,然后把每个任务同它相关的时间点都连接起来,流量限制为1,然后进行你的网络流模版就是了~~
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define MAX 1000000001
#define Max(a,b) a>b?a:b
#define Min(a,b) a<b?a:b
#define M 1111
using namespace std;
int n,m,sum;
struct node
{
int to,val,next;//流向的点,流量限制,下一个对应的点
}s[M*M];//其实就类似做一个线性表
int hand[M],snum;//hand[x]表示x在之前最后出现的那次,在s中的位置,snum是s的长度
int dis[M],q[M];//dis记录dinic算法中用bfs分的层,q是模拟队列
void setit(int from,int to,int
val)
{
s[snum].to=to;//正向,流量限制为输入的这个
s[snum].val=val;
s[snum].next=hand[from];
hand[from]=snum++;
s[snum].to=from;//反向 流量限制初始化为0
s[snum].val=0;
s[snum].next=hand[to];
hand[to]=snum++;
}
int bfs()
{
int i,j,k,l,cur,qian,hou;
memset(dis,-1,sizeof(dis));
qian=hou=0;
q[qian++]=0;
dis[0]=0;
while(qian!=hou)//判断模拟循环队列是否为空
{
cur=q[hou++];//取队首元素并出队
if(hou>=M)hou=0;//循环队列
for(i=hand[cur];i!=-1;i=s[i].next)//线性表中快速遍历与cur相关的点
{
k=s[i].to;//取出点
if(s[i].val>0&&dis[k]==-1)//判断流量限制和是否已经分层
{
dis[k]=dis[cur]+1;//分层
q[qian++]=k;//入队
if(qian>=M)qian=0;//循环队列
if(k==1001)return
1;//已经分层汇点
}
}
}
return 0;//到最后都没有搜到汇点表示没有增广路了
}
int dfs(int x,int flow)
{
int i,j,k,l,cost=0;
if(flow<=0)return
0;
if(x==1001)return
flow;//汇点
for(i=hand[x];i!=-1;i=s[i].next)//遍历相关点
{
k=s[i].to;//取点
if(s[i].val>0&&dis[k]==dis[x]+1)//判断流量限制和层次关系是否符合
{
l=dfs(k,Min(flow-cost,s[i].val));//向下搜索,流量限制取当前剩余流量和路径限制流量中的最小值
if(l>0)//向下搜到汇点则确定这一条路径
{
cost+=l;//当前路径的最小流量加入到总流量消耗值中
s[i].val-=l;//正向减少
s[i^1].val+=l;//反正增加
if(cost==flow)break;//当前点满流则结束
}else dis[k]=-1;//向下搜不到汇点则切断这条路,相当于深搜中vis的作用
}
}
return cost;
}
void dinic()
{
int i,j,k,l=0;
while(bfs())//分层并判断原点是否与汇点相通
{
l+=dfs(0,MAX);//深搜在当前分层中找出最大流
}
if(l>=sum)puts("Yes");//最大流可能大于预判,因为任务在最大时间点之前就全部完成了
else puts("No");
}
int main (void)
{
int t,cas=1,i,j,k,l,Pi,Si,Ei;
scanf("%d",&t);
while(t--&&scanf("%d%d",&n,&m))
{
snum=sum=0;
memset(hand,-1,sizeof(hand));
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&Pi,&Si,&Ei);
setit(0,i,Pi);//我设置的是0为原点,1到n是任务,这里是连接原点跟任务
sum+=Pi;//记录总花费时间
while(Si<=Ei)//遍历当前任务相关的所有时间点
{
setit(i,500+Si,1);//最大任务数是500,所以时间我设置是501到1000,这里是连接任务和相关时间
Si++;
}
}
for(i=501;i<=1000;i++)
setit(i,1001,m);//我设置的汇点是1001,这里是连接所有时间点跟汇点(不管是否在任务范围,这是为了偷懒和方便)
printf("Case %d: ",cas++);
dinic();
puts("");//格式。。
}
return 0;
}
心得:我也是醉了,开始绘图错了,到后来算法时间度我没有深入了解,以至于到了大半夜还在装13卖萌充当学霸,但是给我的收货是学算法不光是了解他的用法和熟练去写它,还需要充分了解它的部分原理,学习其中一些深层的却不起眼的东西,往往这知识点关键时候就是你制胜的关键··
HDU--杭电--3572--Task Schedule--最大流
标签:
原文地址:http://blog.csdn.net/jingdianitnan/article/details/46479729