標籤:style blog http color 使用 os io strong
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=3572
題意:m台機器,需要做n個任務。第i個任務,你需要使用機器Pi天,且這個任務要在[Si , Ei]區間內完成才有效。對於一個任務,只能由一個機器來完成,一個機器同一時間只能做一個任務。當然,一個任務可以分成幾段不連續的時間來完成。問,能否做完全部任務。
題意很清晰,也就是判斷是否是滿流。
對於網路流問題,模板大家都有,關鍵在於如何建圖(詳見資料)
思路:今天問了龍哥,對建圖有了一定的瞭解,建圖分為4部分,源點->X集合->Y集合->匯點(X、Y類似於二分匹配圖),確定這個4個部分後,就是找這個4個部分的關係,也就是構建容量網路
這題的X集合可以當做任務編號,Y集合當做天數(第幾天)
某任務->某一天,若是可以在這天做任務,建一條容量為1的邊,最後,把每天到匯點再建一條邊容量M(表示每台機器最多工作M個任務)即最大容量是M。
以第二組執行個體作圖(真挫。。)
模板應用的是ISAP(可當做模板),個人很傾向ISAP
| Accepted |
2292 KB |
62 ms |
C++ |
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <math.h>#include <queue>#define init(a) memset(a,0,sizeof(a))#define PI acos(-1,0)using namespace std;const int maxn = 1100;const int maxm = 400000;#define lson left, m, id<<1#define rson m+1, right, id<<1|1#define min(a,b) (a>b)?b:a#define max(a,b) (a>b)?a:b#define MAX INT_MAXint head[maxn], sum, bnum;int dis[maxn]; //殘量網路中節點 i 到匯點 t 的最短距離int num[maxn]; //和 t 的最短距離等於 i 的節點數量int cur[maxn]; //當前弧下標int pre[maxn]; //可增廣路上的上一條弧的編號struct node{ int v, cap; int next;}edge[maxm];void add(int u, int v, int cap)//加邊,儲存地圖{ edge[bnum].v=v; edge[bnum].cap=cap; edge[bnum].next=head[u]; head[u]=bnum++; edge[bnum].v = u; edge[bnum].cap=0; edge[bnum].next=head[v]; head[v] = bnum++;}void BFS(int source,int sink)//預先處理,利用反向BFS,更新dis數組{ queue<int>q; while(q.empty()==false) q.pop(); memset(num,0,sizeof(num)); memset(dis,-1,sizeof(dis)); q.push(sink); dis[sink]=0; num[0]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(dis[v] == -1) { dis[v] = dis[u] + 1;//找允許弧 num[dis[v]]++; q.push(v); } } }}int ISAP(int source,int sink,int n)//n為殘量網路中的節點到匯點的最大距離,通常節點的個數{ memcpy(cur,head,sizeof(cur)); int flow=0, u = pre[source] = source; BFS( source,sink);//更新dis數組 while( dis[source] < n ) { if(u == sink) { int df = MAX, pos; for(int i = source;i != sink;i = edge[cur[i]].v)//追蹤增廣路路徑,最小殘量df { if(df > edge[cur[i]].cap) { df = edge[cur[i]].cap; pos = i; } } for(int i = source;i != sink;i = edge[cur[i]].v) //更新流量 { edge[cur[i]].cap -= df; edge[cur[i]^1].cap += df; } flow += df; u = pos; } int st; for(st = cur[u];st != -1;st = edge[st].next)// 從當前弧開始尋找允許弧 { if(dis[edge[st].v] + 1 == dis[u] && edge[st].cap)//找到允許弧跳出 { break; } } if(st != -1) { cur[u] = st; pre[edge[st].v] = u; u = edge[st].v; } else { if( (--num[dis[u]])==0 ) break;//GAP最佳化,出現斷層結束 int mind = n; for(int id = head[u];id != -1;id = edge[id].next)//retreat操作:更新 dis 數組 { if(mind > dis[edge[id].v] && edge[id].cap) { cur[u] = id;//修改標號的同時修改當前弧 mind = dis[edge[id].v]; } } dis[u] = mind+1; num[dis[u]]++; if(u!=source) u = pre[u];// 回溯繼續尋找允許弧 } } return flow;}void initt(){ memset(head,-1,sizeof(head)); bnum=0;}int main(){ int T, N,M,a,b,c; int maa, sum, source, sink, n; scanf("%d", &T); for (int cas = 1; cas <= T; ++cas) { initt(); sum = 0; source = 0; maa = 0; scanf("%d%d", &N, &M); for (int i = 1; i <= N; i++) { scanf("%d%d%d", &a, &b, &c); sum += a; if(c > maa) maa = c; add(source, i, a); for (int j = b; j <= c; ++j) { add(i, N + j, 1); } } sink = N + maa + 1; n = sink; for (int i = 1; i <= maa; ++i) { add(N + i, sink, M); } printf("Case %d: ", cas); int ans = ISAP(source, sink, n); if(ans==sum) puts("Yes"); else puts("No"); cout<<endl; } return 0;}