POJ 3422 费用流

刚开始用dp做一直不过,想不通。

看了别人报告才知道,dp没有解决后效性,即当前的决策会对下一次travel。

出不了数据,但觉得数据大的时候应该会错


这类k次操作,每次操作代价都不同,求最大或者最小代价的问题,只能用费用流

http://hi.baidu.com/graphis/item/74b8afc6ec27f870f6c95d50从多进程动态规划到费用流的转化,这里讲的很好

dp也不是不行,但你要记录之前决策的状态,比如这可能要记录到第k次操作时每个格子被取过了没


边=(容量,代价)

s到起始点建边(k,0),终点到t建边(k,0)

每个点拆点,u->u1  建边 (1,cost) , (k-1,0)

u能转移到v : u1->v : (k,0)


题目还可以变化为,第一次取的代价是多少,第二次去的代价是多少,第三次……做法只要在u->u1 建多几条边 (1,cost) (1,cost) (1,cost) 


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <algorithm>
#include <ctime>
#include <vector>
#include <string>
#include <queue>
using namespace std;
#define N 5500
#define M 55000
struct Edge
{
    int v,cost,cap;
}edge[M];
int adj[M],head[N],e,n,k,src,dest;

int d[N],pre[N],vis[N];

bool spfa()
{
    queue<int>q;
    memset(d,-1,sizeof(d));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    q.push(src);
    d[src]=0;
    vis[src]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;
        for(int i=head[u];i!=-1;i=adj[i])
            if(edge[i].cap && d[edge[i].v] < d[u] + edge[i].cost)
            {
                d[edge[i].v]=d[u]+edge[i].cost;
                pre[edge[i].v]=i;
                // 这里错了!!
                //if(edge[i].v==dest)
                    //return true;
                if(!vis[edge[i].v])
                {
                    vis[edge[i].v]=1;
                    q.push(edge[i].v);
                }
            }
    }
    if(pre[dest]!=-1)
        return true;
    else return false;
}
int cost_flow()
{
    int ans=0;
    while(spfa())
    {
        int u=dest;
        int f=N*3000;
        while(pre[u]!=-1)
        {
            f=min(f,edge[pre[u]].cap);
            u=edge[pre[u]^1].v;
        }
        u=dest;
        while(pre[u]!=-1)
        {
            ans+=edge[pre[u]].cost;
            edge[pre[u]].cap-=1;
            edge[pre[u]^1].cap+=1;
            u=edge[pre[u]^1].v;
        }
    }
    return ans;
}
void addedge(int u,int v,int cap,int cost)
{
    edge[e].v=v;edge[e].cap=cap;edge[e].cost=cost;
    adj[e]=head[u];head[u]=e++;
    edge[e].v=u;edge[e].cap=0;edge[e].cost=-cost;
    adj[e]=head[v];head[v]=e++;
}

int main ()
{
    scanf("%d%d",&n,&k);
    memset(head,-1,sizeof(head));
    e=0;
    src=2*n*n+1;
    dest=2*n*n+2;
    int u;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        {
            scanf("%d",&u);
            addedge((i-1)*n+j,n*n+(i-1)*n+j,1,u);
            addedge((i-1)*n+j,n*n+(i-1)*n+j,k-1,0);
            if(i-1>0)
                addedge(n*n+(i-2)*n+j,(i-1)*n+j,k,0);
            if(j-1>0)
                addedge(n*n+(i-1)*n+j-1,(i-1)*n+j,k,0);
        }
    addedge(src,1,k,0);
    addedge(2*n*n,dest,k,0);

    int ans=cost_flow();
    printf("%d\n",ans);
    return 0;
}



你可能感兴趣的:(POJ 3422 费用流)