hdu 3572 Task Schedule
Task Schedule
题意:有N个任务,M台机器。每一个任务给S,P,E分别表示该任务的(最早开始)开始时间,持续时间和(最晚)结束时间;问每一个任务是否能在预定的时间区间内完成;
注:每一个任务一个时间只能由一台机器加工,(意味着可以随意离散加工的时间点,只要所用的时间点之和为P即可;将天数变成点建图)每一台机器一个时间点也只能加工一个任务;
重点是构图:如果将任务抽象成一个点,所需的时间P变成从该点流出的流量(从源点流入边的容量~~)那么只需按照输入顺序标记为点号与源点s连边,边的容量为P即可;但是点的流量又是怎么"流"出去的呢?流出去只是"时间"问题;即一个任务点最多消耗一个时间点,输入的是一个时间区间(区间很小),我们就可以离散化时间点,之后对区间内的时间点进行连边;边权自然是1了;全部的时间点流向汇点t;边权为机器的数量m;即指每天满载运行时,看是否"最大流"能与s(源点)那边的边权之和(一个割,Yes就表示是最小割)相等;
ps:注意在建立时间点连边的时候,时间点不是之间的Si->Ei;而是在前面n个任务之后;所以标号+n;
Dinic算法;296MS 12452K
#include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> #include<stack> #include<set> using namespace std; #define rep0(i,l,r) for(int i = (l);i < (r);i++) #define rep1(i,l,r) for(int i = (l);i <= (r);i++) #define rep_0(i,r,l) for(int i = (r);i > (l);i--) #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) #define MS0(a) memset(a,0,sizeof(a)) #define MS1(a) memset(a,-1,sizeof(a)) #define inf 0x3f3f3f3f typedef __int64 ll; template<typename T> void read1(T &m) { T x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m = x*f; } template<typename T> void read2(T &a,T &b){read1(a);read1(b);} template<typename T> void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} template<typename T> void out(T a) { if(a>9) out(a/10); putchar(a%10+'0'); } const int N = 1000; const int M = 101000; int head[N],tot; struct Edge{ int from,to,cap,flow,Next; Edge(){} Edge(int from,int to,int cap,int Next):from(from),to(to),cap(cap),flow(0),Next(Next){} }e[M<<1]; inline void ins(int u,int v,int w) { //cout<<" ........... "<<u<<" "<<v<<" "<<w<<endl; e[tot] = Edge{u,v,w,head[u]}; head[u] = tot++; } int vis[M],s,t,cur[M],d[M]; queue<int> Q; int BFS() { rep1(i,s,t) vis[i] = 0; vis[s] = 1;d[s] = 0; Q.push(s); while(!Q.empty()){ int u = Q.front();Q.pop(); for(int i = head[u];~i;i = e[i].Next){ int v = e[i].to; if(!vis[v] && e[i].cap > e[i].flow){ // 只考虑残量网络的弧 vis[v] = 1; d[v] = d[u] + 1; Q.push(v); } } } return vis[t]; } int DFS(int x,int a)// a表示目前为止所有弧的最小残量 { if(x == t || a == 0) return a; int& i = cur[x];//回溯时会多次DFS到同一个点 if(i == 0) i = head[x]; int flow = 0, f; for(;~i;i = e[i].Next){// 从上次考虑的弧开始 int v = e[i].to; if(d[v] == d[x]+1 && (f = DFS(v,min(a,e[i].cap - e[i].flow))) > 0){ e[i].flow += f; e[i^1].flow -= f; flow += f; a -= f;// 残量-流量 if(a == 0) break; } } return flow; } int Dinic() { int flow = 0; while(BFS()){//在残量网络基础上不断刷新层次图; rep1(i,s,t) cur[i] = 0;//记录当前探索到的点的弧的编号 flow += DFS(s,inf); } return flow; } int main() { int n,m,T,kase = 1; read1(T); while(T--){ s = 0; int mn = inf,mx = 0,sum = 0; MS1(head);tot = 0; read2(n,m); rep1(i,1,n){ int P,S,E; read3(P,S,E); sum += P; mn = min(mn,S); mx = max(mx,E); ins(i,s,P);ins(s,i,P); rep1(j,n+S,n+E){//与日期连边的时候要注意标号 ins(i,j,1);ins(j,i,1); } } t = n+mx+1; rep1(i,n+mn,n+mx){ ins(i,t,m);ins(t,i,m); } //cout<<mn<<" "<<mx<<endl; printf("Case %d: %s",kase++,sum == Dinic()?"Yes":"No"); puts("");puts(""); } return 0; }
ISAP一直处于RE状态。。无语了。上面Dinic代码原本数组是开小了的,但是过了。在ISAP中改好了,却一直RE。不知道还有其他的原因会导致RE..找不出来
先贴一发;若看出bug,直接评论即可
#include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> #include<stack> #include<set> using namespace std; #define rep0(i,l,r) for(int i = (l);i < (r);i++) #define rep1(i,l,r) for(int i = (l);i <= (r);i++) #define rep_0(i,r,l) for(int i = (r);i > (l);i--) #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) #define MS0(a) memset(a,0,sizeof(a)) #define MS1(a) memset(a,-1,sizeof(a)) #define inf 0x3f3f3f3f typedef __int64 ll; template<typename T> void read1(T &m) { T x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m = x*f; } template<typename T> void read2(T &a,T &b){read1(a);read1(b);} template<typename T> void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} template<typename T> void out(T a) { if(a>9) out(a/10); putchar(a%10+'0'); } const int N = 1110; const int M = 505000; int head[N],tot; struct Edge{ int from,to,cap,flow,Next; Edge(){} Edge(int from,int to,int cap,int Next):from(from),to(to),cap(cap),flow(0),Next(Next){} }e[M]; inline void ins(int u,int v,int cap) { //cout<<" ........... "<<u<<" "<<v<<" "<<w<<endl; e[tot] = Edge{u,v,cap,head[u]}; head[u] = tot++; } int d[N],s,t; queue<int> Q; void BFS()//逆向求解到汇点的最短距离; { rep1(i,s,t) d[i] = inf; d[t] = 0; Q.push(t); while(!Q.empty()){ int v = Q.front();Q.pop(); for(int i = head[v];~i;i = e[i].Next){ int u = e[i].to;// 还是to;无向边 if(d[u] > d[v] + 1 && e[i].cap > e[i].flow){ d[u] = d[v] + 1; Q.push(u); } } } } int cur[N],num[N],p[N]; int Augment() { int x = t,a = inf; while(x != s){ //从汇点逆推得到可改进量a; a = min(a, e[p[x]].cap - e[p[x]].flow); x = e[p[x]].from; } x = t; while(x != s){ // 逆推,进行增广 e[p[x]].flow += a; e[p[x]^1].flow -= a; x = e[p[x]].from; } return a; } int Maxflow() { BFS(); MS0(num); rep1(i,s,t) num[d[i]]++; int x = s,flow = 0; MS0(cur); while(d[s] < t){ if(x == t){ flow += Augment(); x = s; } int ok = 0,id = cur[x]; if(id == 0) id = head[x]; for(;~id;id = e[id].Next){ int v = e[id].to; if(d[x] == d[v] + 1 && e[id].cap > e[id].flow){ ok = 1; p[v] = id;//前进中记录下路径的标号;以v为索引; cur[x] = id;//记录下当前u点的弧,和Dinic一样为了优化 x = v; break; } } if(!ok){//点x没有找到可行的弧,认为原因出在d[] if(--num[d[x]] == 0) break;//gap优化 因为d[x] < dist + 1;中间断层 int dist = t - 1;// **后面dist + 1即当该点在残余网络中没有从x出发的弧,d[x] = t; for(int id = head[x];~id;id = e[id].Next){ if(e[id].cap > e[id].flow) dist = min(dist, d[e[id].to]); } num[d[x]=dist+1]++; cur[x] = 0; if(x != s) x = e[p[x]].from;//往回走是因为可能当前的节点不存在增广路了; } } return flow; } int main() { int n,m,T,kase = 1; read1(T); while(T--){ s = 0; int mn = inf,mx = 0,sum = 0; MS1(head);tot = 0; read2(n,m); rep1(i,1,n){ int P,S,E; read3(P,S,E); sum += P; mn = min(mn,S); mx = max(mx,E); ins(i,s,P);ins(s,i,P); rep1(j,n+S,n+E){//与日期连边的时候要注意标号 ins(i,j,1);ins(j,i,1); } } t = n+mx+1; rep1(i,n+mn,n+mx){ ins(i,t,m);ins(t,i,m); } printf("Case %d: %s",kase++,sum == Maxflow()?"Yes":"No"); puts("");puts(""); } return 0; }