http://www.sdutacm.org/sdutoj/showproblem.php?pid=2414&cid=1744
最小费用最大流,开始ps用贪心,每次找出最大高度或者最小高度的插入,然后如果最大高度的能插入则插最大的,否则就插小的,(注意插入时候需要贪心两步)感觉是可以的,但是最终问题出在哪里好像还不知道。
一个不错的网址:http://www.hardbird.net/%E5%B1%B1%E4%B8%9C%E7%9C%81%E7%AC%AC%E4%B8%89%E5%B1%8A%E7%9C%81%E8%B5%9B-c-%E9%A2%98-an-interesting-game%E8%B4%B9%E7%94%A8%E6%B5%81/
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <queue> using namespace std; const int maxn=2200; const int oo=0x3f3f3f3f; struct Edge { int u, v, cap, flow, cost;Edge(){} Edge(int u, int v, int cap, int flow, int cost):u(u), v(v), cap(cap), flow(flow), cost(cost) {} }; struct MCMF { int n, m, s, t; vector<Edge> edge; vector<int> G[maxn]; int inq[maxn], d[maxn], p[maxn], a[maxn]; void init(int n) { this->n=n; for(int i=0; i<n; i++) G[i].clear(); edge.clear(); } void AddEdge(int u, int v, int cap, int cost) { edge.push_back(Edge(u, v, cap, 0, cost)); edge.push_back(Edge(v, u, 0, 0, -cost)); m=edge.size(); G[u].push_back(m-2); G[v].push_back(m-1); } bool spfa(int s, int t, int& flow, int& cost) { memset(d, 0x3f, sizeof d); memset(inq, 0, sizeof inq); d[s]=0, inq[s]=1, p[s]=0, a[s]=oo; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=0; i<G[u].size(); i++) { Edge& e=edge[G[u][i]]; if(e.cap>e.flow && d[e.v]>d[u]+e.cost) { d[e.v]=d[u]+e.cost; p[e.v]=G[u][i]; a[e.v]=min(a[u], e.cap-e.flow); if(!inq[e.v]) { q.push(e.v); inq[e.v]=1; } } } } if(d[t]==oo)return false; flow+=a[t]; cost+=d[t]*a[t]; int u=t; while(u!=s) { edge[p[u]].flow+=a[t]; edge[p[u]^1].flow-=a[t]; u=edge[p[u]].u; } return true; } int MinCost(int s, int t) { int flow=0, cost=0; while(spfa(s, t, flow, cost)); return cost; } } net; int a[maxn], b[maxn]; int main() { int T, kase=0; scanf("%d", &T); while(T--) { int n, m, k, ans=0; scanf("%d%d%d", &n, &m, &k); net.init(n+100); memset(b, 0, sizeof b); for(int i=0; i<n; i++) scanf("%d", a+i); for(int i=0; i<m; i++) { int x; scanf("%d", &x); b[x]++; } for(int i=1; i<n; i++) { ans+=abs(a[i]-a[i-1]); net.AddEdge(0, i, 1, 0); for(int j=0; j<=30; j++) if(b[j]) { int dis=abs(a[i]-j)+abs(a[i-1]-j)-abs(a[i]-a[i-1]); net.AddEdge(i, n+j, 1, -dis); } } int S=n+50, T=S+1; for(int i=0; i<=30; i++) if(b[i]) net.AddEdge(i+n, T, b[i], 0); net.AddEdge(S, 0, k, 0); printf("Case %d: %d\n", ++kase, ans-net.MinCost(S, T)); } return 0; }