题目大意:给出学生的数目和学习小组的数目,学生参加小组需要交纳费用,每个小组会支出C[i]*cnt[i]^2。每个学生可以参加k个小组,问最多的学生参加时,最小支出费用。
思路:如果不算后面那个什么鬼的条件的话,见图十分显然。
S->每个学生 f:k,c:0
每个学生->每个学习小组 f:1,c:-F[i]
每个学习小组->T f:1,c:1 * C[i],3 * C[i],5 * C[i],7 * C[i],......
后面的条件其实是说,每个学生的k次机会不一定全用光,但是所有人都要参加至少一个小组。于是我们可以每个人->T f:k - 1,c:0
然后跑费用流
CODE:
#define _CRT_SECURE_NO_DEPRECATE #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 510 #define MAXE 200010 #define INF 0x3f3f3f3f #define S 0 #define T (MAX - 1) using namespace std; struct MinCostMaxFlow{ int head[MAX],total; int next[MAXE],aim[MAXE],flow[MAXE],cost[MAXE]; int from[MAX],p[MAX]; int f[MAX]; bool v[MAX]; MinCostMaxFlow() { total = 1; } void Add(int x,int y,int f,int c) { next[++total] = head[x]; aim[total] = y; flow[total] = f; cost[total] = c; head[x] = total; } void Insert(int x,int y,int f,int c) { Add(x,y,f,c); Add(y,x,0,-c); } bool SPFA() { static queue<int> q; while(!q.empty()) q.pop(); memset(f,0x3f,sizeof(f)); memset(v,false,sizeof(v)); f[S] = 0; q.push(S); while(!q.empty()) { int x = q.front(); q.pop(); v[x] = false; for(int i = head[x]; i; i = next[i]) if(flow[i] && f[aim[i]] > f[x] + cost[i]) { f[aim[i]] = f[x] + cost[i]; if(!v[aim[i]]) v[aim[i]] = true,q.push(aim[i]); from[aim[i]] = x; p[aim[i]] = i; } } return f[T] != INF; } int EdmondsKarp() { int re = 0; while(SPFA()) { int max_flow = INF; for(int i = T; i != S; i = from[i]) max_flow = min(max_flow,flow[p[i]]); for(int i = T; i != S; i = from[i]) { flow[p[i]] -= max_flow; flow[p[i]^1] += max_flow; } re += f[T] * max_flow; } return re; } }solver; int points,groups,k; int C[MAX],F[MAX]; bool map[MAX][MAX]; int main() { cin >> points >> groups >> k; for(int i = 1; i <= groups; ++i) scanf("%d",&C[i]); for(int i = 1; i <= groups; ++i) scanf("%d",&F[i]); for(int i = 1; i <= points; ++i) for(int j = 1;j <= groups; ++j) scanf("%1d",&map[i][j]); for(int i = 1; i <= points; ++i) { solver.Insert(S,i,k,0); for(int j = 1; j <= groups; ++j) if(map[i][j]) solver.Insert(i,points + j,1,-F[j]); } if(k - 1) for(int i = 1; i <= points; ++i) solver.Insert(i,T,k - 1,0); for(int i = 1; i <= groups; ++i) for(int j = 1; j <= points; ++j) solver.Insert(i + points,T,1,((j << 1) - 1) * C[i]); cout << solver.EdmondsKarp() << endl; return 0; }
时间: 2024-10-11 23:02:15