河南省第六届acm省赛 探寻宝藏&& poj 3422 (最大费用最大流)

来源:互联网 发布:黑蚂蚁网络电视 编辑:程序博客网 时间:2024/06/05 02:36

题目描述

传说HMH大沙漠中有一个M*N迷宫,里面藏有许多宝物。某天,Dr.Kong找到了迷宫的地图,他发现迷宫内处处有宝物,最珍贵的宝物就藏在右下角,迷宫的进出口在左上角。当然,迷宫中的通路不是平坦的,到处都是陷阱。Dr.Kong决定让他的机器人卡多去探险。

但机器人卡多从左上角走到右下角时,只会向下走或者向右走。从右下角往回走到左上角时,只会向上走或者向左走,而且卡多不走回头路。(即:一个点最多经过一次)。当然卡多顺手也拿走沿路的每个宝物。

Dr.Kong希望他的机器人卡多尽量多地带出宝物。请你编写程序,帮助Dr.Kong计算一下,卡多最多能带出多少宝物。

输入

第一行: K     表示有多少组测试数据。 

接下来对每组测试数据:

1:       M   N

2~M+1行: Ai1  Ai2 ……AiN    (i=1,..,m)

2k5      1M, N50     0Aij100    (i=1,.,M; j=1,,N)

所有数据都是整数。 数据之间有一个空格。

输出

对于每组测试数据,输出一行:机器人卡多携带出最多价值的宝物数

样例输入

22 30 10 1010 10 803 30 3 92 8 55 7 100

样例输出

120134
题意:左上走到右下捡数字,走两次,求最大和
求最大费用最大流只需把费用变成负数,用spfa找到一条费用最大的路
还有就是要拆点建图,一个点拆成两个,其中一条边费用为对应数字,流量1,另一条边费用为0,流量1
然后设个超级源点和超级汇点,分别连接左上,右下
这个和poj3422有些类似,那个题是走k次,这个只走两次
拆点建图,建完的图,就是每个点拆为两个,1&1',s→1→→1’→2→→2' 然后1↓3→→3'→4→→4’
大概就这个意思,上下左右也要连起来
代码注释:                                   
#include<iostream>#include<cstring>#include<algorithm>#include<queue>using namespace std;#define N 5050#define inf 0x7fffffffint n,m,s,t,maxflow,o;struct node{    int u,v,c,f,next;} a[100000];int visit[N];int pre[N];int head[N];int dis[N];int map[55][55];void add(int u,int v,int c,int f) //c为费用,f流量{    a[o].u=u,a[o].v=v,a[o].c=c,a[o].f=f;    a[o].next=head[u],head[u]=o++;    a[o].u=v,a[o].v=u,a[o].c=-c,a[o].f=0;//建立反边    a[o].next=head[v],head[v]=o++;}int spfa(){    int i,u,v;    memset(visit,0,sizeof(visit));    memset(pre,-1,sizeof(pre));    for(i=0; i<=t; i++)        dis[i]=inf;    queue<int>q;    while(!q.empty())        q.pop();    q.push(s);    visit[s]=1;    dis[s]=0;    while(!q.empty())    {        u=q.front();        q.pop();        for(i=head[u]; i!=-1; i=a[i].next)        {            v=a[i].v;            if(a[i].f>0&&dis[u]+a[i].c<dis[v])            {                dis[v]=dis[u]+a[i].c;                pre[v]=i;                if(!visit[v])                {                    visit[v]=1;                    q.push(v);                }            }        }        visit[u]=0;    }    if(dis[t]==inf)        return 0;    return 1;}void Add()//修改残留网络{    int i;    int mm=inf;    for(i=pre[t]; a[i].u!=s; i=pre[a[i].u])//找到最小可增流        mm=min(mm,a[i].f);    for(i=pre[t]; a[i].u!=s; i=pre[a[i].u])    {        a[i].f-=mm;        a[i^1].f+=mm;//修改        maxflow+=mm*a[i].c;//加到maxflow中    }}int main(){    int T,i,j,x;    cin>>T;    while(T--)    {        cin>>n>>m;        o=0;        maxflow=0;        memset(head,-1,sizeof(head));        for(i=1; i<=n; i++)            for(j=1; j<=m; j++)                cin>>map[i][j];        for(i=1; i<=n; i++)            for(j=1; j<=m; j++)            {                x=(i-1)*m+j-1;                add(2*x,2*x+1,-map[i][j],1);//拆点构图,费用置为负                add(2*x,2*x+1,0,1);            }        for(i=1; i<=n; i++)            for(j=1; j<m; j++)//向右边建图            {                x=(i-1)*m+j-1;                add(2*x+1,2*(x+1),0,2);            }        for(i=1; i<n; i++)            for(j=1; j<=m; j++)//向下边建图            {                x=(i-1)*m+j-1;                add(x*2+1,2*(x+m),0,2);            }        s=n*m*2;        t=n*m*2+1;        add(s,0,0,2);        add(n*m*2-1,t,0,2);//连接源点汇点        while(spfa())            Add();        cout<<-maxflow<<endl;    }}


这里再贴出poj 3422 题目连接:点击打开链接
题意上面说过了
代码:
#include<iostream>//和上面那题对比,这个是个n*n的 建图时好建,然后拆点,一条边流量为1,另一条为k-1#include<cstring>#include<queue>using namespace std;#define M 5050#define N 100000#define inf 0x7ffffffstruct node{    int u,v,c,f,next;} a[N];int head[M];int visit[M];int pre[M];int dis[M];int s,t,maxflow,num,k,n;void add(int u,int v,int c,int f){    a[num].u=u;    a[num].v=v;    a[num].f=f;    a[num].c=c;    a[num].next=head[u];    head[u]=num++;    a[num].u=v;    a[num].v=u;    a[num].f=0;    a[num].c=-c;    a[num].next=head[v];    head[v]=num++;}int spfa(){    memset(pre,-1,sizeof(pre));    memset(visit,0,sizeof(visit));    for(int i=0; i<=t; i++)        dis[i]=inf;    dis[s]=0;    queue<int>q;    visit[s]=1;    q.push(s);    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=head[u]; i!=-1; i=a[i].next)        {            int v=a[i].v;            if(a[i].f>0&&dis[u]+a[i].c<dis[v])            {                dis[v]=dis[u]+a[i].c;                pre[v]=i;                if(!visit[v])                {                    visit[v]=1;                    q.push(v);                }            }        }        visit[u]=0;    }    if(dis[t]==inf)        return 0;    return 1;}void Add(){    int v;    int mm=inf;    for(v=pre[t]; a[v].u!=s; v=pre[a[v].u])        mm=min(mm,a[v].f);    for(v=pre[t]; a[v].u!=s; v=pre[a[v].u])    {        a[v].f-=mm;        a[v^1].f+=mm;        maxflow+=mm*a[v].c;    }}int map[100][100];int main(){    while(cin>>n>>k)    {        maxflow=0;        s=n*n*2;        t=s+1;        num=0;        memset(head,-1,sizeof(head));        for(int i=1; i<=n; i++)            for(int j=1; j<=n; j++)                cin>>map[i][j];        for(int i=1; i<=n; i++)            for(int j=1; j<=n; j++)            {                int b=(i-1)*n+j-1;                add(b*2,2*b+1,-map[i][j],1);                add(b*2,b*2+1,0,k-1);            }        for(int i=1; i<=n; i++)            for(int j=1; j<n; j++)            {                int b=(i-1)*n+j-1;                add(2*b+1,2*(b+1),0,k);            }        for(int i=1; i<n; i++)            for(int j=1; j<=n; j++)            {                int b=(i-1)*n+j-1;                add(b*2+1,2*(b+n),0,k);            }        add(s,0,0,k);        add(n*n*2-1,t,0,k);        while(spfa())            Add();        cout<<-maxflow<<endl;    }}


0 0