HDU 4862 Jump 最大费用最大流

题意:给一个矩阵,可以选择任意的一个点,作为起点,上面的人可以向下或者向右跳,他的花费是|x1-x2|+|y1-y2|-1,如果他跳一步的起点和终点上的数字一样的,那么他就可以赚到数字的价格。以上叙述是一轮游戏,现在最多可以进行k轮游戏,有一个条件,每一个格子只能走一次,而且每一个格子都要走到。问完成游戏最多可以赚多少?


想法:有两个关键点,每个格子必须走,且走一次,还有一点就是最多k轮游戏。

费用流解决:

1.虚拟source,fucksource,sink

2.source向fucksource连一条容量为k费用为0的边

解释:游戏最多进行k轮这里的边,表示正好k轮游戏。

3.fucksource向sink连一条容量为inf费用为0的边

解释:因为有可能不需要k轮游戏,就可以解决战斗。

4.a点拆成a,a',a向a'连一条容量为1,费用为inf的边

解释:应为每一个格子必须要走,容量为1是为了限制每一个格子只能走一次,对于这里的费用为什么要设置为inf,接着往下看

5.fucksource向a连一条容量为1,费用为0的边

解释:选择一个起点,每一个点都可能是起点,所以连接所有点

6.a'向sink连一条容量为1,费用为0的边

解释:选择一个终点,每一个点都可能是终点,所以连接所有点

7.a'向b(另外一个点,拆点之后的)连一条容量为1,费用为所求的的边

解释:这个人可以从a跳到哪里,所有可能的点都连上

其实网络流就相当于图的暴力。下面解释为什么我的把a->a'的费用置为inf,首先明确,要找最长路,每个点必须找到,因为拆点只能保证这个点只能被用一次或者不用,但是我们并不可以确定到底是用了还是没有用,当把费用置为inf时,如果这个点被选择那么一条最长路上必定会有这一个inf值,那么最后取到的最大费用里面,如果满足题目要求那么必定会有n*m个点的inf被加了进去,所以如果最大费用-n*m*inf,如果它的值小于0表示有的点并没有走到,如果大于0表示这就是最后答案。

提示:每一次找到一条最长路它的值去掉对应的inf它的值一定大于等于0,因为,当你一次跳一个格子的时候,你是不会产生花费的。


#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define inf 10000
using namespace std;
const int nodes=200+5;
const int edges=5000;
int n,m,k,s,ss,t,totfee;
char map[15][15];
struct node 
{
    int u,v,next;
    int flow,fee;
}e[edges];
int head[nodes],cur[nodes],cnt;
class Dinic
{
    public:
        int spfa()
        {
            queue<int>q;
            while(!q.empty()) q.pop();
            for(int i=s;i<=t;i++)
            {
                dis[i]=-inf;
            }
            memset(vis,0,sizeof(vis));
            memset(pe,-1,sizeof(pe));
            vis[s]=1;
            dis[s]=0;
            q.push(s);
            while(!q.empty())
            {
                int u=q.front();
                q.pop();
                vis[u]=0;
                for(int i=head[u];i+1;i=e[i].next)
                {
                    int v=e[i].v;
                    if(dis[v]<dis[u]+e[i].fee&&e[i].flow>0)
                    {
                        dis[v]=dis[u]+e[i].fee;
                        pe[v]=i;
                        if(!vis[v])
                        {
                            vis[v]=1;
                            q.push(v);
                        }
                    }
                }
            }
            return dis[t]!=-inf;
        }
        int Min(int a,int b)
        {
            if(a<b) return a;
            return b;
        }
        int dfs(int u,int flow)
        {
            int cost=0;
            if(u==t)
            {
                totfee+=dis[t];
                return flow;
            }
            for(int &i=cur[u];i+1;i=e[i].next)
            {
                int v=e[i].v;
                if(pe[v]==i&&e[i].flow>0)
                {
                    int minn=dfs(v,Min(e[i].flow,flow-cost));
                    if(minn>0)
                    {
                        e[i].flow-=minn;
                        e[i^1].flow+=minn;
                        cost+=minn;
                        if(cost==flow) break;
                    }
                    else pe[v]=-1;
                }
            }
            return cost;
        }
        void result()
        {
            while(spfa())
            {
                for(int i=s;i<=t;i++) cur[i]=head[i];
                int pp=dfs(s,inf);
            }
        }
    private:
        int dis[nodes],vis[nodes],pe[nodes];
}dinic;
void Init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
void add(int a,int b,int flow,int fee)
{
    e[cnt].v=b;
    e[cnt].flow=flow;
    e[cnt].fee=fee;
    e[cnt].next=head[a];
    head[a]=cnt++;
    
    e[cnt].v=a;
    e[cnt].flow=0;
    e[cnt].fee=-fee;
    e[cnt].next=head[b];
    head[b]=cnt++;
}
int aabs(int x)
{
    if(x>0) return x;
    return -x;
}
void build_map()
{
    s=0;ss=2*n*m+1;t=2*n*m+2;
    add(s,ss,k,0);
    add(ss,t,inf,0);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int num=(i-1)*m+j;
            add(ss,num,1,0);
            add(num+n*m,t,1,0);
            add(num,num+n*m,1,inf);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int u=(i-1)*m+j;
            for(int l=j+1;l<=m;l++)
            {
                int v=(i-1)*m+l;
                int dis=aabs(j-l)-1;
                if(map[i][j]!=map[i][l]) add(u+m*n,v,1,0-dis);
                else
                {
                    int w=map[i][j]-'0'-dis;
                    add(u+n*m,v,1,w);
                }
            }
            for(int l=i+1;l<=n;l++)
            {
                int v=(l-1)*m+j;
                int dis=aabs(l-i)-1;
                if(map[i][j]!=map[l][j]) add(u+m*n,v,1,0-dis);
                else
                {
                    int w=map[i][j]-'0'-dis;
                    add(u+n*m,v,1,w);
                }
            }
        }
    }
}
void treatment(int ca)
{
    totfee=0;
    dinic.result();
    int ans=totfee-n*m*inf;
    printf("Case %d : ",ca);
    if(ans<0) printf("-1\n");
    else printf("%d\n",ans);
}
int main()
{
    int test,ca=1;
    scanf("%d",&test);
    while(test--)
    {
        Init();
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
        scanf("%s",map[i]+1);
        build_map();
        treatment(ca++);
    }
    return 0;
}



你可能感兴趣的:(HDU 4862 Jump 最大费用最大流)