志愿者招募
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了志愿者招募相关的知识,希望对你有一定的参考价值。
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。
Input
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。
Output
仅包含一个整数,表示你所设计的最优方案的总费用。
Sample Input
3 3
2 3 4
1 2 2
2 3 5
3 3 2
Sample Output
14
看到这道题就有一种套路感 ,qwq 。
我们将原点和第一时刻 ,然后第一时刻与第二时刻 ,这样依次连边
因为只有下界没有上界,所有容量连为inf-ai ,
然后将si和ti+1直接连一条(inf , cost)的边。
这是我想到的比较简单的做法 , 而某大神的做法我只能%%,
附上链接:https://www.byvoid.com/blog/noi-2008-employee/#more-916
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 const int inf = 1 << 30 , maxn = 1000 + 11 ; 7 using namespace std ;//1061109567 8 int m , n , head[maxn] , dis[maxn] , s ,t ,ans , cnt ; 9 bool mark[maxn] ; 10 struct id 11 { 12 int to , nxt , val , vol ; 13 } edge[50012] ; 14 queue< int > Q ; 15 16 inline void Init ( ) 17 { 18 freopen( "NSOOJ#10366.in" , "r" , stdin ) ; 19 freopen( "NSOOJ#10366.out" , "w" , stdout ) ; 20 } 21 22 int read( ) 23 { 24 char ch = getchar( ) ; int k = 1 , ret = 0 ; 25 while( ch < ‘0‘ || ch > ‘9‘ ) { if( ch == ‘-‘ ) k = -1 ; ch = getchar( ) ; } 26 while( ch >= ‘0‘ && ch <= ‘9‘ ) ret = ret * 10 + ch - ‘0‘ , ch = getchar( ) ; 27 return k * ret ; 28 } 29 30 void add( int u , int v , int va , int vo ) 31 { 32 edge[++cnt].nxt = head[u] , edge[cnt].to = v ; 33 edge[cnt].val = va , edge[cnt].vol = vo , head[u] = cnt ; 34 } 35 36 void input( ) 37 { 38 int n , m ; n = read( ) , m = read( ) ; 39 s = 1 , t = n + 2 ;int a ; cnt = -1; 40 memset( head , -1 , sizeof(head) ) ; 41 add( 1 , 2 , inf , 0 ) ; add( 2 , 1 , inf , 0 ) ; 42 for( int x = 1 ; x <= n ; ++x ) 43 { 44 a = read( ) ; 45 add( x+1 , x+2 , inf - a , 0 ) ; 46 add( x+2 , x+1 , 0 , 0 ) ; 47 } 48 int i , j , k ; 49 for( int x = 1 ; x <= m ; ++x ) 50 { 51 i = read( ) , j = read( ) , k = read( ) ; 52 add( i+1 , j+2 , inf , k ) ; 53 add( j+2 , i+1 , 0 , 0-k ) ; 54 } 55 } 56 57 bool spfa( ) 58 { 59 memset( mark , 0 , sizeof(mark) ) ; 60 memset( dis , 127/2 , sizeof(dis) ) ; 61 mark[t] = 1 ; dis[t] = 0 ; Q.push( t ) ; 62 while( !Q.empty( ) ) 63 { 64 int u = Q.front( ) ; Q.pop( ) ; 65 for( int i = head[u] ; ~i ; i = edge[i].nxt ) 66 { 67 68 int v = edge[i].to ; 69 if( edge[i^1].val && dis[v] > dis[u] + edge[i^1].vol ) 70 { 71 dis[v] = dis[u] + edge[i^1].vol ; 72 if( !mark[v] ) 73 { 74 mark[v] = 1 ; 75 Q.push( v ) ; 76 } 77 } 78 79 } 80 mark[u] = false ; 81 } 82 return dis[s] != 1061109567 ; 83 } 84 85 86 int dfs( int u , int f ) 87 { 88 mark[u] = true ; 89 if( u == t ) return f ; 90 int w , used = 0 ; 91 for( int i = head[u] ; ~i ; i = edge[i].nxt ) 92 { 93 int v = edge[i].to ; 94 if( dis[v] == dis[u] - edge[i].vol && edge[i].val && !mark[v] ) 95 { 96 w = f - used ; 97 w = dfs( v , min( w , edge[i].val ) ) ; 98 ans += w * edge[i].vol ; 99 edge[i].val -= w , edge[i^1].val += w ; used += w ; 100 if( used == f ) return used ; 101 } 102 } 103 return used ; 104 } 105 106 107 void zkw( ) 108 { 109 int sum = 0 ; 110 while( spfa( ) ) 111 { 112 mark[t] = 1 ; 113 while( mark[t] ) 114 { 115 memset( mark , 0 , sizeof(mark) ) ; 116 sum = dfs( s , inf ) ; 117 } 118 } 119 printf( "%d\n" , ans ) ; 120 } 121 122 123 int main( ) 124 { 125 // Init( ) ; 126 input( ) ; 127 zkw( ) ; 128 // fclose( stdin ) ; 129 // fclose( stdout ) ; 130 return 0 ; 131 }
以上是关于志愿者招募的主要内容,如果未能解决你的问题,请参考以下文章