HDU--杭電--3572--Task Schedule--最大流
Task Schedule
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5031 Accepted Submission(s): 1642
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
題意:給你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
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賣萌充當學霸,但是給我的收貨是學演算法不光是瞭解他的用法和熟練去寫它,還需要充分了解它的部分原理,學習其中一些深層的卻不起眼的東西,往往這知識點關鍵時候就是你制勝的關鍵··