第三届山东ACM省赛 An interesting game

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;
} 



你可能感兴趣的:(第三届山东ACM省赛 An interesting game)