1. 程式人生 > >HDU 3572 Task Schedule[Dinic多路增廣優化]

HDU 3572 Task Schedule[Dinic多路增廣優化]

Task Schedule

題意:有n個任務,每個任務三個引數,P,S,E,分別代表需要工作的時間,起始時間,終止時間. 工作的P天可以不連續.每天可以同時進行M個任務.問,是否有合理的安排計劃.

思路:

  • 每個任務對於區間[S,E]連一條邊,代表這些路徑都可以嘗試
  • 對於每個任務,從源點S流入P的流量
  • 對於每一天,都流向一個匯點T,容量為M

這樣建好圖後,跑一遍最大流,若$$ MAXFlow=\sum_{i=1}^n p[i]$$證明一定有合理的計劃

Accepted 3572 452MS 3380K 2120B G++

按理說Dinic的複雜度是$$ O(n^2*m) $$. 題目中 n->1000 , m->5e5 . 但Dinic對於某些特殊的圖,跑的特快

對於邊容量都是1的情況,複雜度為$$ O(min(N^{0.67},M^{0.5})*M) $$

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e3+3,M=6e5;
const int inf=1e9+9;
int cnt;
int ver[M<<1],edge[M<<1],Next[M<<1],head[N<<1];

void add(int u,int v,int w){
    ver[++cnt]=v;edge[cnt]=w;Next[cnt]=head[u];head[u]=cnt;
}
void init(){
    memset(head,-1,sizeof head);
    cnt=1;
}
int s,t;
int dis[N];
bool bfs(){
    memset(dis,0,sizeof dis);
    dis[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];i!=-1;i=Next[i]){
            if(edge[i]>0 && !dis[ver[i]]){
                dis[ver[i]]=dis[x]+1;
                q.push(ver[i]);
                if(ver[i]==t)   return true;
            }
        }
    }
    return false;
}

int Dinic(int x,int flow){
    if(x==t || flow==0)    return flow;
    int res=0;
    for(int i=head[x];i!=-1;i=Next[i]){
        if( flow-res>0&&dis[ver[i]]==dis[x]+1&& edge[i]){ ///flow-res>0 少一次遞迴,優化
            int k=Dinic(ver[i],min(flow-res,edge[i]));
            if(!k)  dis[ver[i]]=0;
            edge[i]-=k;
            edge[i^1]+=k;
            res+=k;
        }
    }
    return res;
}
int ks;
bool vis[600];
int main(void){
    int m,n;
    int T;
    scanf("%d",&T);
    while(T--){
        memset(vis,false,sizeof vis);
        int mn=999,mx=0;
        scanf("%d%d",&n,&m);
        init();
        s=0,t=500+n+1;
        ll tot=0;
        for(int i=1;i<=n;i++){
            int p,st,ed;
            scanf("%d%d%d",&p,&st,&ed);
            tot+=p;
            add(s,500+i,p);
            add(500+i,s,0);
            for(int j=st;j<=ed;j++){
                add(500+i,j,1);
                add(j,500+i,0);
                vis[j]=true;
            }
        }
        for(int i=1;i<=500;i++){
            if(!vis[i]) continue;
            add(i,500+n+1,m);
            add(500+n+1,i,0);
        }
        ll maxflow=0;
        int flow;
        while(bfs()){
            while(flow=Dinic(s,inf)) maxflow+=flow;
        }
//        cout << maxflow <<endl;
        printf("Case %d: ",++ks);
        if(maxflow==tot)    printf("Yes\n\n");
        else    printf("No\n\n");
    }
    return 0;
}