poj 3422 Kaka's Matrix Travels hdu 3376 matrix again 费用流

这两题有一个共同的特点,都是从矩阵的左上角走到右下角,求最大能获得的权值

不过poj 3422可以走k次

 

poj  3422

每个点走过一次后,这个点的权值就置零了,相当于经过一次后以后每次经过都没有费用了,所以每个点拆点后u->u'  建两条边 

一条边容量为1 费用为负的点权

另一条边容量为INF,费用为0

 

另外如果一个点能到另一个点,还是老方法u'->v,容量为INF,费用为0;

最后要限制总流量为k,即建一个源点向1建一条容量为k,费用为0的边     n*n*2(最后一个点的出点) 向汇点连一条容量为k费用为0的边

最后求一下S、T的最小费用流即可

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int sumFlow;
const int MAXN = 720010;
const int MAXM = 1000010;
const int INF = 1000000000;
struct Edge
{
    int u, v, cap, cost;
    int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
    NE = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
    edge[NE].next = head[u]; head[u] = NE++;
    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
    edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
    int i, u, v;
    queue <int> qu;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i = 0; i <= n; i++) dist[i] = INF;
    vis[s] = true; dist[s] = 0;
    qu.push(s);
    while(!qu.empty())
    {
        u = qu.front(); qu.pop(); vis[u] = false;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)
            {
                dist[v] = dist[u] + edge[i].cost;
                pp[v] = i;
                if(!vis[v])
                {
                    qu.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    if(dist[t] == INF) return false;
    return true;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
    int flow = 0; // 总流量
    int i, minflow, mincost;
    mincost = 0;
    while(SPFA(s, t, n))
    {
        minflow = INF + 1;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
            if(edge[i].cap < minflow)
                minflow = edge[i].cap;
        flow += minflow;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
        {
            edge[i].cap -= minflow;
            edge[i^1].cap += minflow;
        }
        mincost += dist[t] * minflow;
    }
    sumFlow = flow; // 题目需要流量,用于判断
    return mincost;
}
int main()
{
    int n,i,j,x,k;
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%d",&k);
        init();
        int S=0,T=n*n*2+1;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&x);
                int u=(i-1)*n+j;
                addedge(u,u+n*n,INF,0);
                addedge(u,u+n*n,1,-x);
                if(i<n) addedge(u+n*n,u+n,INF,0);
                if(j<n) addedge(u+n*n,u+1,INF,0);
            }
        }
        addedge(S,1,k,0);
        addedge(n*n*2,T,k,0);
        printf("%d\n",-MCMF(S,T,T+1));
    }
}

 

 

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int sumFlow;
const int MAXN = 720010;
const int MAXM = 1000010;
const int INF = 1000000000;
struct Edge
{
    int u, v, cap, cost;
    int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
    NE = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
    edge[NE].next = head[u]; head[u] = NE++;
    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
    edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
    int i, u, v;
    queue <int> qu;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i = 0; i <= n; i++) dist[i] = INF;
    vis[s] = true; dist[s] = 0;
    qu.push(s);
    while(!qu.empty())
    {
        u = qu.front(); qu.pop(); vis[u] = false;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)
            {
                dist[v] = dist[u] + edge[i].cost;
                pp[v] = i;
                if(!vis[v])
                {
                    qu.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    if(dist[t] == INF) return false;
    return true;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
    int flow = 0; // 总流量
    int i, minflow, mincost;
    mincost = 0;
    while(SPFA(s, t, n))
    {
        minflow = INF + 1;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
            if(edge[i].cap < minflow)
                minflow = edge[i].cap;
        flow += minflow;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
        {
            edge[i].cap -= minflow;
            edge[i^1].cap += minflow;
        }
        mincost += dist[t] * minflow;
    }
    sumFlow = flow; // 题目需要流量,用于判断
    return mincost;
}
int main()
{
    int n,i,j,x,k;
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%d",&k);
        init();
        int S=1,T=n*n*2;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&x);
                int u=(i-1)*n+j;
                addedge(u,u+n*n,1,-x);
                addedge(u,u+n*n,k-1,0);
                if(i<n) addedge(u+n*n,u+n,INF,0);
                if(j<n) addedge(u+n*n,u+1,INF,0);
            }
        }
        if(k==0)
        {
            puts("0");
            continue;
        }
        //addedge(S,1,k,0);
        //addedge(n*n*2,T,k,0);
        printf("%d\n",-MCMF(S,T,T));
    }
}

 

 

hdu 3376

这题注意开大空间啊,空间没开够错了好几次 

因为每个点只能经过一次,立刻就联想到了拆点

源点有2的容量,汇点也有2的容量 即s-s'容量为2,费用为点权

建好图后求一次最小费用最大流即可

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int sumFlow;
const int MAXN = 720010;
const int MAXM = 1000010;
const int INF = 1000000000;
struct Edge
{
    int u, v, cap, cost;
    int next;
}edge[MAXM<<2];
int NE;
int head[MAXN], dist[MAXN], pp[MAXN];
bool vis[MAXN];
void init()
{
    NE = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
    edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost;
    edge[NE].next = head[u]; head[u] = NE++;
    edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost;
    edge[NE].next = head[v]; head[v] = NE++;
}
bool SPFA(int s, int t, int n)
{
    int i, u, v;
    queue <int> qu;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i = 0; i <= n; i++) dist[i] = INF;
    vis[s] = true; dist[s] = 0;
    qu.push(s);
    while(!qu.empty())
    {
        u = qu.front(); qu.pop(); vis[u] = false;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].cap && dist[v] > dist[u] + edge[i].cost)
            {
                dist[v] = dist[u] + edge[i].cost;
                pp[v] = i;
                if(!vis[v])
                {
                    qu.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    if(dist[t] == INF) return false;
    return true;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
    int flow = 0; // 总流量
    int i, minflow, mincost;
    mincost = 0;
    while(SPFA(s, t, n))
    {
        minflow = INF + 1;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
            if(edge[i].cap < minflow)
                minflow = edge[i].cap;
        flow += minflow;
        for(i = pp[t]; i != -1; i = pp[edge[i].u])
        {
            edge[i].cap -= minflow;
            edge[i^1].cap += minflow;
        }
        mincost += dist[t] * minflow;
    }
    sumFlow = flow; // 题目需要流量,用于判断
    return mincost;
}
int main()
{
    int n,i,j,x;
    while(scanf("%d",&n)!=EOF)
    {
        init();
        int S=1,T=n*n*2;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&x);
                int u=(i-1)*n+j;
                addedge(u,u+n*n,1,-x);
                if(i<n) addedge(u+n*n,u+n,1,0);
                if(j<n) addedge(u+n*n,u+1,1,0);
            }
        }
        addedge(1,1+n*n,1,0);
        addedge(n*n,n*n*2,1,0);
        printf("%d\n",-MCMF(S,T,T));
    }
}
posted @ 2012-04-11 14:24  Because Of You  Views(486)  Comments(0Edit  收藏  举报