当前位置: 首页 > news >正文

三取方格数

三取方格数

时间限制: 1 Sec  内存限制: 128 MB

题目描述

设有N*N的方格图,我们将其中的某些方格填入正整数,
而其他的方格中放入0。
某人从图得左上角出发,可以向下走,也可以向右走,直到到达右下角。
在走过的路上,他取走了方格中的数。(取走后方格中数字变为0)
此人从左上角到右下角共走3次,试找出3条路径,使得取得的数总和最大。

 

输入

第一行:N (4<=N<=20)
接下来一个N*N的矩阵,矩阵中每个元素不超过80,不小于0

 

输出

一行,表示最大的总和。

 

样例输入

4
1 2 3 4
2 1 3 4
1 2 3 4
1 3 2 4

样例输出

39
题解:
法一:
DP
f[x1][y1][x2][x3]第一个人走到(x1,y1),第二个人走到(x2,x1+y1-x2),第三个人走到(x3,x1+y1-x3)总和最大值 

(x1-1,y1)->(x1,y1)向右 (x2,x1-1+y1-x2)->(x2,x1+y1-x2)向下 (x3,x1-1+y1-x3)->(x3,x1+y1-x3)向下 

(x1-1,y1)->(x1,y1)向右 (x2,x1-1+y1-x2)->(x2,x1+y1-x2)向下 (x3-1,x1+y1-x3)->(x3,x1+y1-x3)向右  

(x1-1,y1)->(x1,y1)向右 (x2-1,x1+y1-x2)->(x2,x1+y1-x2)向右 (x3,x1-1+y1-x3)->(x3,x1+y1-x3)向下  

(x1-1,y1)->(x1,y1)向右 (x2-1,x1+y1-x2)->(x2,x1+y1-x2)向右 (x3-1,x1+y1-x3)->(x3,x1+y1-x3)向右 

(x1,y1-1)->(x1,y1)向下 (x2,x1+y1-1-x2)->(x2,x1+y1-x2)向下,(x3,x1+y1-1-x3)->(x3,x1+y1-x3)向下 

(x1,y1-1)->(x1,y1)向下 (x2,x1+y1-1-x2)->(x2,x1+y1-x2)向下,(x3-1,x1+y1-x3)->(x3,x1+y1-x3)向右 

(x1,y1-1)->(x1,y1)向下 (x2-1,x1+y1-x2)->(x2,x1+y1-x2)向右,(x3,x1+y1-1-x3)->(x3,x1+y1-x3)向下 

(x1,y1-1)->(x1,y1)向下 (x2-1,x1+y1-x2)->(x2,x1+y1-x2)向右,(x3-1,x1+y1-x3)->(x3,x1+y1-x3)向右 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=21;
int gi()
{
    int str=0;
    char ch=getchar();
    while(ch>'9' || ch<'0')ch=getchar();
    while(ch>='0' && ch<='9')str=str10+ch-48,ch=getchar();
    return str;
}
int f[N*2][N][N][N],a[N][N];
int main()
{
    int n=gi();
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            a[i][j]=gi();
    int tmp=0,from,to;
    for(int i=1; i<n+n; i++)
    {
        from=i-n+1>1?i-n+1:1;
        to=i<n?i:n;
        for(int j=from; j<=to; j++)
        {
            for(int k=from; k<=to; k++)
            {
                for(int g=from; g<=to; g++)
                {
                    tmp=0;
                    if(f[i-1][j][k][g]>tmp)tmp=f[i-1][j][k][g];
                    if(f[i-1][j-1][k][g]>tmp)tmp=f[i-1][j-1][k][g];
                    if(f[i-1][j][k-1][g]>tmp)tmp=f[i-1][j][k-1][g];
                    if(f[i-1][j][k][g-1]>tmp)tmp=f[i-1][j][k][g-1];
                    if(f[i-1][j-1][k-1][g]>tmp)tmp=f[i-1][j-1][k-1][g];
                    if(f[i-1][j-1][k][g-1]>tmp)tmp=f[i-1][j-1][k][g-1];
                    if(f[i-1][j][k-1][g-1]>tmp)tmp=f[i-1][j][k-1][g-1];
                    if(f[i-1][j-1][k-1][g-1]>tmp)tmp=f[i-1][j-1][k-1][g-1];
                    f[i][j][k][g]=tmp+a[j][i-j+1];
                    if(j!=k)f[i][j][k][g]+=a[k][i-k+1];
                    if(g!=k && g!=j)f[i][j][k][g]+=a[g][i-g+1];
                }
            }
        }
    }
    printf("%d",f[n+n-1][n][n][n]);
    return 0;
}

 

法二:
网络流——最大费用最大流。

具体算法如下:

拆点建图,每一个点都拆成两个点,在这里就称为出点和入点。

出点和入点建两条边,一条费用为s[i][j],流量为1;一条费用为0,流量为inf。(分别表示选择这个点和从这个点上经过)

将(i,j)的出点分别和(i+1,j)(i,j+1)的入点建边,流量为inf,费用为0。(表示行进)

跑一边最大费用最大流就可以了。

额~~~鼓掌鼓掌。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#define inf (2e8)
using namespace std;
int n,m;
int ans;
struct node
{
    int next,to,cost,cap;
} edge[500001];
int size=1,head[20001],s[51][51];
void putin(int from,int to,int cap,int cost)
{
    size++;
    edge[size].next=head[from];
    edge[size].to=to;
    edge[size].cap=cap;
    edge[size].cost=cost;
    head[from]=size;
}
void in(int from,int to,int cap,int cost)
{
    putin(from,to,cap,cost);
    putin(to,from,0,-cost);
}
void build()
{
    int i,j;
    in(0,1,3,0);//源点和1建边 
    in(n*n*2,n*n*2+1,3,0);//末节点和汇点建边 
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
        {
            in((i-1)*n+j,(i-1)*n+j+n*n,1,s[i][j]);//一条费用为s[i][j],流量为1的边 
            in((i-1)*n+j,(i-1)*n+j+n*n,inf,0);//一条费用为0,流量为inf的边 
            if(i!=n)in((i-1)*n+j+n*n,i*n+j,inf,0);
            if(j!=n)in((i-1)*n+j+n*n,(i-1)*n+j+1,inf,0);//和连接点建边,注意一下临界条件 
        }
    }
}
int f[300001],pre[300001],vis[300001];
bool bfs(int src,int des)
{
    int i;
    for(i=0; i<=n*n*2+1; i++)
    {
        f[i]=-1;
        vis[i]=0;
    }
    queue<int>mem;
    mem.push(src);
    f[src]=0;
    vis[src]=1;
    while(!mem.empty())
    {
        int x=mem.front();
        mem.pop();
        vis[x]=0;
        for(i=head[x]; i!=-1; i=edge[i].next)
        {
            int y=edge[i].to;
            if(edge[i].cap&&f[y]<f[x]+edge[i].cost)
            {
                f[y]=f[x]+edge[i].cost;
                pre[y]=i;
                if(!vis[y])
                {
                    mem.push(y);
                    vis[y]=1;
                }
            }
        }
    }
    if(f[des]==-1)return 0;
    else return 1;
}//最大费用最大流,求的是最长路,因此初值为-1 
void change(int src,int des)
{
    int x=des,flow=2e8;
    while(x!=src)
    {
        flow=min(flow,edge[pre[x]].cap);
        x=edge[pre[x]^1].to;
    }
    x=des;
    while(x!=src)
    {
        ans+=flow*edge[pre[x]].cost;
        edge[pre[x]].cap-=flow;
        edge[pre[x]^1].cap+=flow;
        x=edge[pre[x]^1].to;
    }
}//反过来修改每一条边的流量,并计算ans的值,edge[i^1]为edge[i]的反向边 
void max_cost_flow(int src,int des)
{
    while(bfs(src,des))change(src,des);
}
int main()
{
    memset(head,-1,sizeof(head));
    int i,j;
    scanf("%d",&n);
    for(i=1; i<=n; i++)
        for(j=1; j<=n; j++)
            scanf("%d",&s[i][j]);
    build();
    max_cost_flow(0,n*n*2+1);
    printf("%d",ans);
    return 0;
}

 

 

 

 

转载于:https://www.cnblogs.com/huangdalaofighting/p/6951868.html

相关文章:

  • Hibernate拦截器(Interceptor)与事件监听器(Listener)
  • 把时间格式12:59:00 转换成小时数,并保留一位小数
  • 如何查看oracle当前session信息
  • 《放弃的艺术》晨读笔记
  • SpringMVC的入门例子
  • 交叉排序
  • 漫画 —— Linux 内核结构图
  • Memcached Tip 2:Session同步
  • 关于软件设计,我们都错了
  • eureka
  • 嵌入式外部中断控制编程方法论—比較CC2541(51核)和S5PV210(ARM核)
  • 创建Activiti的25张表
  • Flume性能测试报告(翻译Flume官方wiki报告)
  • C#多线程环境下调用 HttpWebRequest 并发连接限制
  • mysql之 mysql 5.6不停机主主搭建(活跃双主基于日志点复制)
  • 【node学习】协程
  • 2017-09-12 前端日报
  • Angular 4.x 动态创建组件
  • CSS魔法堂:Absolute Positioning就这个样
  • github从入门到放弃(1)
  • If…else
  • Java,console输出实时的转向GUI textbox
  • JavaScript创建对象的四种方式
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Rancher-k8s加速安装文档
  • tensorflow学习笔记3——MNIST应用篇
  • 初识MongoDB分片
  • 基于axios的vue插件,让http请求更简单
  • 看域名解析域名安全对SEO的影响
  • 如何实现 font-size 的响应式
  • 想写好前端,先练好内功
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 正则表达式
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • 数据可视化之下发图实践
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • #define用法
  • #pragma预处理命令
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (一)Linux+Windows下安装ffmpeg
  • (转)EXC_BREAKPOINT僵尸错误
  • .a文件和.so文件
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .NET6 命令行启动及发布单个Exe文件
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .NET学习教程二——.net基础定义+VS常用设置
  • .NET值类型变量“活”在哪?
  • @GetMapping和@RequestMapping的区别