1. 程式人生 > >[vijos1891]學姐的逛街計劃

[vijos1891]學姐的逛街計劃

spa head jos map 代碼 style () names ostream

分析: 可以記第i天去不去逛街為a[i],第i天智商為val[i]; 設: p[1] = a[1] + a[2] + …… + a[n] <= k; p[2] = a[2] + a[3] + …… + a[n + 1] <= k …… p[n * 2 + 1] = a[n * 2 + 1] + a[n * 2 + 2] + …… + a[3 * n] <= k 然後添加輔助變量y[i],設q[i] = p[i] + y[i] = k 可得: q[1] = p[1] +y[1] = k q[2] = p[2] +y[2] = k …… q[n * 2 + 1] = p[n * 2 + 1] +y[n * 2 + 1] = k 添加 輔助變量 q[0] = 0,q[n * 2 + 2] = 0 依次相減得到: q[1] - q[0] = a[1] + a[2] + …… + a[n] + y[1] = k; ---- 1 q[2] - q[1] = a[n + 1] - a[1] + y[2] - y[1] = 0; ----2 q[3] - q[2] = a[n + 2] - a[2] + y[3] - y[2] = 0;----3 …… q[n * 2 + 2] - q[n * 2 + 1] = - a[n * 2 + 1] - a[n * 2 + 2] - …… - a[3 * n] - y[n * 2 + 1] = -k;-----n * 2 + 2 可以發現每一個變量都在等式中出現了兩次,並且一次為正,一次為負,正相對於網絡流中的流量守恒,流進等於流出(實際流量即為變量的值) 於是我們可以把每個等式看成一個點。把源點和第一個點連流量為k,花費為0。匯點和最後一個點連流量為k,花費為0; 對於每一個a[i]把它在等式中為正的點連向它在等式中為負的點,流量為1,花費為-val[i]。(因為求最大費用最大流,花費取負數後答案再倒回來就行) 對於每一個y[i]把它在等式中為正的點連向它在等式中為負的點,流量為k,花費為0。 然後求一遍最小費用最大流,答案取相反數(這樣變成了最大費用最大流),就為我們要的答案。 貼上AC代碼:
  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <queue>
  5 using namespace std;
  6 const int N = 1e4;
  7 const int M = 4e5;
  8 const int INF = 0x3f3f3f3f;
  9 using namespace std;
 10 struct Edge
 11 {
 12     int from, to, cap, flow, cost, next;
13 }; 14 Edge edge[M]; 15 int head[N], inde,pre[N], dist[N]; 16 bool vis[N]; 17 int n,k; 18 void init() 19 { 20 inde = 0; 21 memset(head, -1, sizeof(head)); 22 } 23 void AddEdge(int u, int v, int w, int c) 24 { 25 Edge E1 = {u, v, w, 0, c, head[u]}; 26 edge[inde] = E1; 27
head[u] = inde++; 28 Edge E2 = {v, u, 0, 0, -c, head[v]}; 29 edge[inde] = E2; 30 head[v] = inde++; 31 } 32 bool SPFA(int s, int t) 33 { 34 queue<int> Q; 35 memset(dist, INF, sizeof(dist)); 36 memset(vis, false, sizeof(vis)); 37 memset(pre, -1, sizeof(pre)); 38 dist[s] = 0; 39 vis[s] = true; 40 Q.push(s); 41 while(!Q.empty()) 42 { 43 int u = Q.front(); 44 Q.pop(); 45 vis[u] = false; 46 for(int i = head[u]; i != -1; i = edge[i].next) 47 { 48 Edge E = edge[i]; 49 if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow) 50 { 51 dist[E.to] = dist[u] + E.cost; 52 pre[E.to] = i; 53 if(!vis[E.to]) 54 { 55 vis[E.to] = true; 56 Q.push(E.to); 57 } 58 } 59 } 60 } 61 return pre[t] != -1; 62 } 63 void MCMF(int s, int t, int &cost, int &flow) 64 { 65 flow = 0; 66 cost = 0; 67 while(SPFA(s, t)) 68 { 69 int Min = INF; 70 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 71 { 72 Edge E = edge[i]; 73 Min = min(Min, E.cap - E.flow); 74 } 75 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 76 { 77 edge[i].flow += Min; 78 edge[i^1].flow -= Min; 79 cost += edge[i].cost * Min; 80 } 81 flow += Min; 82 } 83 } 84 int cnt,s,t; 85 int node[503],val[603]; 86 int st[603],en[603]; 87 void getMap(){ 88 s = ++cnt;t = ++cnt; 89 for(int i = 1;i <= n * 2 + 2;i++){ 90 node[i] = ++cnt; 91 }for(int i = 1;i <= 3 * n;i++)scanf("%d",&val[i]); 92 AddEdge(s,node[1],k,0); 93 AddEdge(node[n * 2 + 2],t,k,0); 94 for(int i = 1;i <= n;i++)st[i] = node[1]; 95 for(int i = n + 1;i <= 3 * n;i++)st[i] = node[i - n + 1]; 96 for(int i = 1;i <= 2 * n;i++)en[i] = node[i + 1]; 97 for(int i = 2 * n + 1;i <= 3 * n;i++)en[i] = node[n * 2 + 2]; 98 for(int i = 1;i <= 3 * n;i++)AddEdge(st[i],en[i],1,-val[i]); 99 for(int i = 1;i <= 2 * n + 1;i++)AddEdge(node[i],node[i + 1],k,0); 100 } 101 int main() 102 { 103 scanf("%d %d",&n,&k); 104 init(); 105 getMap(); 106 int cost, flow; 107 MCMF(s,t, cost, flow); 108 printf("%d\n",-cost); 109 return 0; 110 }

[vijos1891]學姐的逛街計劃