第一次面对建模的图,也映照了我以前想的算法不是重点,问题的转化才是重点
Description:
N个任务,M台机器,对于每一个任务有p,s,e表示该任务要做p个时长,要从[s,……)开始,从(……e]结束,问你这些任务最后能完成吗Yes || No
Solution:
做的是最大流专辑,知道是最大流的题目,但是就是不知道怎么转化为最大流的问题。。。
Yes or No的关键就是最大流能否等于任务总时长,面对这个题,对于每一个任务 i ,从源点到i添加一条边,边的权值(容量)是对应任务的p,如果yes是不是从s流出的量 fmax == sum(p),假设这些流量流到了任务,那么任务如何处理呢,就是看看时间段如何分配,因为可以任意时间段开始,暂停直到结束所以每个任务与它对应的每一个时间段都要添加一个1(容量),不管这个任务咋分配,只要能分配给它的p就行了,那分配好时间段了呢,是不是还有一个条件也就是机器数目,同一个时间最多m个机器工作,所以每一个时间段,都要向汇点T,传入一个m的容量,表示的意义也很明显啦,最后求出最大流就好了!真舒服,第一次懂一类题的感觉应该都是这样的吧略略略
要注意一下,最多有多少边哈·
#include <iostream> #include <cstdio> #include <string.h> #include <queue> #include <cmath> #include <algorithm> #define inf (1 << 28) using namespace std; typedef long long ll; const int maxn = 5000; const int maxm = 251000+7; int n,m; int S,T; struct node{ int pre; int to,cost; }e[maxm<<1]; int id[maxn],cnt; int flor[maxn]; int cur[maxn];//DFS的优化遍历 void add(int from,int to,int cost) { e[cnt].to = to; e[cnt].cost = cost; e[cnt].pre = id[from]; id[from] = cnt++; swap(from,to); e[cnt].to = to; e[cnt].cost = 0; e[cnt].pre = id[from]; id[from] = cnt++; } int bfs(int s,int t) { memset(flor,0,sizeof(flor)); queue < int > q; while(q.size())q.pop(); flor[s] = 1; q.push(s); while(q.size()) { int now = q.front(); q.pop(); for(int i = id[now];~i;i=e[i].pre) { int to = e[i].to; int cost = e[i].cost; if(flor[to] == 0 && cost > 0) { flor[to] = flor[now] + 1; q.push(to); if(to == t)return 1; } } } return 0; } int dfs(int s,int t,int value) { //ret表示目前流到s的最大流量,用来计算回溯的时候是否还有可行流 int ret = value; if(s == t || value == 0)return value; int a; for(int &i = cur[s];~i;i = e[i].pre) { int to = e[i].to; int cost = e[i].cost; if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,cost)))) { e[i].cost -= a; e[i^1].cost += a; ret -= a; if(ret == 0)break; } } //s点后面没有可行的流了 if(ret == value) flor[s] = 0; return value - ret; } int dinic(int s,int t) { ll ret = 0; while(bfs(s,t)) { memcpy(cur,id,sizeof(id)); ret += dfs(s,t,inf); } return ret; } void init() { memset(id,-1,sizeof(id)); cnt = 0; } int main() { int t; scanf("%d",&t); int cas = 0; while(t--) { scanf("%d%d",&n,&m); init(); int p,s,e; int tl = -1,tr = -1; S = 0; int sump = 0; for(int i = 1;i <= n;++i) { scanf("%d%d%d",&p,&s,&e); sump += p; add(S,i,p); if(tl == -1)tl = s; if(tr == -1)tr = e; tl = min(tl,s); tr = max(tr,e); for(int j = s;j <= e;++j) { add(i,n+j,1); } } T = n + tr + 1; for(int i = tl;i <= tr;++i) { add(n + i,T,m); } ll ret = dinic(S,T); printf("Case %d: %s ",++cas,ret == sump ? "Yes" : "No"); } return 0; }