cf 164 C 费用流

2024-09-09 08:18
文章标签 费用 cf 164

本文主要是介绍cf 164 C 费用流,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

给你n个任务,k个机器,n个任务的起始时间,持续时间,完成任务的获利

每个机器可以完成任何一项任务,但是同一时刻只能完成一项任务,一旦某台机器在完成某项任务时,直到任务结束,这台机器都不能去做其他任务

最后问你当获利最大时,应该安排那些机器工作,即输出方案

具体建图方法:

新建源汇S T‘

对任务按照起始时间s按升序排序

拆点:

u 向 u'连一条边 容量为 1 费用为 -c,

u' 向 T连一条边 容量为 inf 费用为 0;

如果任务u完成后接下来最先开始的是任务v

则从u' 向 v连一条边,容量inf 费用 0.

另外,任务从前往后具有传递性,所以必须是第i个任务向第i+1个任务建边,容量为inf

最后,限制一下起始点向第一个任务的流量即可(即K)

const int maxn = 5000 ;
const int maxm = 50000 ;
const int inf = 1000000000 ;
struct Edge{int v , f , w , next ;int u ;Edge(){}Edge(int _v , int _f , int _w , int _next):v(_v),f(_f),w(_w),next(_next){}
};
int  g[maxn + 10] ;
Edge e[maxm + 10] ;
int  source , meet ;
int  id ;void  add(int u , int v  , int f , int w){e[++id] = Edge(v , f , w , g[u]) ;e[id].u = u ;g[u] = id ;e[++id] = Edge(u , 0 , -w , g[v]) ;e[id].u = v ;g[v] = id ;
}queue<int> que ;
bool in[maxn + 10] ;
int  dist[maxn + 10] ;
int  pv[maxn + 10] , pe[maxn + 10] ;int bfs(){while(! que.empty()) que.pop() ;que.push(source) ;memset(dist , 63 , sizeof(dist)) ;dist[source] = 0  ;in[source] = 1 ;while(! que.empty()){int u = que.front() ; que.pop() ;in[u] = 0 ;for(int i = g[u] ; i ; i = e[i].next){int  v = e[i].v ;if(e[i].f > 0 && dist[u] + e[i].w < dist[v]){dist[v] = dist[u] + e[i].w ;pv[v] = u ;pe[v] = i ;if(! in[v]){in[v] = 1 ;  que.push(v) ;}}}}return  dist[meet] < inf  ;
}int  augment(){int u = meet  ;int delta = inf ;while(u != source){delta = min(delta , e[pe[u]].f) ;u = pv[u] ;}u = meet ;while(u != source){e[pe[u]].f -= delta ;e[pe[u] ^ 1].f += delta ;u = pv[u] ;}return dist[meet] * delta ;
}int  mincostflow(){int ans = 0 ;while(bfs())  ans += augment() ;return ans ;
}void init(){memset(g , 0 , sizeof(g)) ;id = 1 ;
}struct  Task{int s , e , val , id ;friend bool operator < (const Task A , const Task B){return A.s < B.s ;}
}tk[1008] ;
int   ans[1008] ;int   main(){int n , k  , i , j , u , v ;while(cin>>n>>k){for(i = 1 ; i <= n ; i++){scanf("%d%d%d" , &tk[i].s , &tk[i].e , &tk[i].val) ;tk[i].e = tk[i].s + tk[i].e - 1 ;tk[i].id = i ;}sort(tk+1 , tk+1+n) ;init() ;source = 0 , meet = 2*n + 1 ;for(i = 1 ; i <= n ; i++){add(i , i+n , 1 , -tk[i].val) ;add(i+n , meet , inf , 0) ;for(j = i + 1 ; j <= n ; j++){if(tk[i].e < tk[j].s){add(i+n , j , inf , 0) ;break ;}}if(i < n) add(i , i+1 , inf , 0) ;}add(source , 1 , k , 0) ;add(n , meet , k , 0) ;mincostflow() ;memset(ans , 0 , sizeof(ans)) ;for(i = 2 ; i <= id ; i+=2){u = e[i].u , v = e[i].v ;if(e[i].f == 0){if(u != source && v != meet && u <= n)ans[tk[u].id] = 1 ;}}for(i = 1 ; i <= n ; i++)printf("%d " , ans[i]) ;puts("") ;}return 0 ;
}


这篇关于cf 164 C 费用流的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1150627

相关文章

poj 2175 最小费用最大流TLE

题意: 一条街上有n个大楼,坐标为xi,yi,bi个人在里面工作。 然后防空洞的坐标为pj,qj,可以容纳cj个人。 从大楼i中的人到防空洞j去避难所需的时间为 abs(xi - pi) + (yi - qi) + 1。 现在设计了一个避难计划,指定从大楼i到防空洞j避难的人数 eij。 判断如果按照原计划进行,所有人避难所用的时间总和是不是最小的。 若是,输出“OPETIMAL",若

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了

最大流、 最小费用最大流终极版模板

最大流  const int inf = 1000000000 ;const int maxn = 20000 , maxm = 500000 ;struct Edge{int v , f ,next ;Edge(){}Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){}};int sourse , mee

CF 508C

点击打开链接 import java.util.Arrays;import java.util.Scanner;public class Main {public static void main(String [] args){new Solve().run() ;} }class Solve{int bit[] = new int[608] ;int l

【CF】C. Glass Carving(二分 + 树状数组 + 优先队列 + 数组计数)

这题简直蛋疼死。。。。。 A了一下午 #include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int maxn = 200005;int h,w,n;int C1[maxn],C2[maxn];int

【CF】E. Anya and Cubes(双向DFS)

根据题意的话每次递归分3种情况 一共最多25个数,时间复杂度为3^25,太大了 我们可以分2次求解第一次求一半的结果,也就是25/2 = 12,记录结果 之后利用剩余的一半求结果 s-结果 = 之前记录过的结果 就可以 时间复杂度降低为 3 ^ (n/2+1) 题目链接:http://codeforces.com/contest/525/problem/E #include<set

【CF】D. Arthur and Walls(BFS + 贪心)

D题 解题思路就是每次检查2X2的方格里是否只有一个‘*’,如果有的话这个*就需要变成‘.’,利用BFS进行遍历,入队的要求是这个点为. 一开始将所有的'.'全部加入队列,如果碰到一个'*'变成'.'就入队,判断的时候从4个方向就行判断 题目链接:http://codeforces.com/contest/525/problem/D #include<cstdio>#include<