NOI题库 / 2.6基本算法之动态规划 - 7614:最低通行费

总时间限制: 
1000ms

内存限制: 
65536kB
描述

一个商人穿过一个 N*N 的正方形的网格,去参加一个非常重要的商务活动。他要从网格的左上角进,右下角出。每穿越中间1个小方格,都要花费1个单位时间。商人必须在(2N-1)个单位时间穿越出去。而在经过中间的每个小方格时,都需要缴纳一定的费用。

这个商人期望在规定时间内用最少费用穿越出去。请问至少需要多少费用?

注意:不能对角穿越各个小方格(即,只能向上下左右四个方向移动且不能离开网格)。

输入
第一行是一个整数,表示正方形的宽度N (1 <= N < 100);
后面 N 行,每行 N 个不大于 100 的整数,为网格上每个小方格的费用。
输出
至少需要的费用。
样例输入
5
1 4 6 8 10
2 5 7 15 17
6 8 9 18 20
10 11 12 19 21
20 23 25 29 33 
样例输出
109
提示
样例中,最小值为109=1+2+5+7+9+12+19+21+33。
来源
元培-From Whf
题目链接
费用流 

#include <cstdio>
#include <queue>
#define M 100000
#define N 105
#define inf 0x3f3f3f3f

using namespace std;
bool inq[N];
int n,S,T,cnt=1,fx[5]= {1,-1,0,0},fy[5]= {0,0,-1,1},a[N][N],to[M<<1],dis[M],fa[M],head[M],came[M<<1],nxt[M<<1],flow[M<<1],cost[M<<1];
void ins(int u,int v,int w,int f)
{
    nxt[++cnt]=head[u];to[cnt]=v;flow[cnt]=w;cost[cnt]=f;head[u]=cnt;
    nxt[++cnt]=head[v];to[cnt]=u;flow[cnt]=0;cost[cnt]=-f;head[v]=cnt;
}
bool spfa()
{
    for(int i=S; i<=T; ++i) dis[i]=inf,inq[i]=false,came[i]=inf;
    queue<int>q;
    dis[S]=0;
    q.push(S);
    for(int u; !q.empty();)
    {
        u=q.front();
        q.pop();
        inq[u]=false;
        for(int i=head[u]; i; i=nxt[i])
        {
            int v=to[i];
            if(dis[v]>dis[u]+cost[i]&&flow[i])
            {
                dis[v]=dis[u]+cost[i];
                fa[v]=i;
                came[v]=min(came[u],flow[i]);
                if(!inq[v])
                {
                    inq[v]=true;
                    q.push(v);
                }
            }
        }
    }
    return dis[T]<inf;
}
int main(int argc,char *argv[])
{
    scanf("%d",&n);
    S=0;
    T=n*n*2+1;
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=n; ++j)
            scanf("%d",&a[i][j]);
    ins(S,1,inf,a[1][1]);
    ins(n*n,T,inf,0);
    for(int i=1; i<=n; ++i)
    {
        for(int j=1; j<=n; ++j)
        {
            ins((i-1)*n+j,(i-1)*n+j+n*n,1,0);
            for(int k=0; k<4; ++k)
            {
                int ti=i+fx[k],tj=j+fy[k];
                if(ti<1||ti>n||tj<1||tj>n) continue;
                ins((i-1)*n+j+n*n,(ti-1)*n+tj,1,a[ti][tj]);
            }
        }
    }
    int ans=0;
    while(spfa())
    {
        int t=came[T];
        for(int i=T; i!=S; i=to[fa[i]^1])
        {
            flow[fa[i]]-=t;
            flow[fa[i]^1]+=t;
        }
        ans+=t*dis[T];
    }
    printf("%d\n",ans);
    return 0;
}

dp

#include<iostream>
using namespace std;
int n,a[118][118],f[118][118];
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
        {
            cin>>a[i][j];
            if(j==1)
                f[i][j]=f[i-1][j]+a[i][j];
            else if(i==1)
                f[i][j]=f[i][j-1]+a[i][j];
            else
                f[i][j]=min(f[i-1][j]+a[i][j],f[i][j-1]+a[i][j]);
        }
    cout<<f[n][n];
    return 0;
}

时间: 2024-10-06 15:07:19

NOI题库 / 2.6基本算法之动态规划 - 7614:最低通行费的相关文章

NOI题库 / 2.6基本算法之动态规划 - 8471:切割回文

总时间限制:  1000ms 内存限制:  65536kB 描述 阿福最近对回文串产生了非常浓厚的兴趣. 如果一个字符串从左往右看和从右往左看完全相同的话,那么就认为这个串是一个回文串.例如,"abcaacba"是一个回文串,"abcaaba"则不是一个回文串. 阿福现在强迫症发作,看到什么字符串都想要把它变成回文的.阿福可以通过切割字符串,使得切割完之后得到的子串都是回文的. 现在阿福想知道他最少切割多少次就可以达到目的.例如,对于字符串"abaacca

NOI题库 1768最大子矩阵 题解

NOI题库 1768最大子矩阵  题解 总时间限制: 1000ms 内存限制: 65536kB 描述 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的矩阵 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 的最大子矩阵是 9 2 -4 1 -1 8 这个子矩阵的大小是15. 输入   输入是一个N * N的矩阵.输入的第一行给出N (0 < N <= 100).再后面的若干行中,依

[NOI题库]1.1题解

今年NOIP居然"各有两道题目从NOI题库中抽取并在原题基础上改动后使用",不好好刷题怎么行. 这是第一篇题解文章,因为题目太水直接上代码了. 1.1编程基础之输入输出 01 Hello, World! 根据题意直接输出"Hello, World!"即可. #include <iostream> using namespace std; int main() { cout<<"Hello, World!"<<e

[NOI题库]1.3编程基础之算术表达式与顺序执行 题解(一)

01 A+B问题 经典的A+B Problem——各大题库上的首题.读入$a,b$,输出$a+b$. #include <iostream> using namespace std; int main() { int a,b; cin>>a>>b; cout<<a+b<<endl; return 0; } 01.cpp 02 计算(a+b)*c的值 读入$a,b,c$,输出$c(a+b)$. #include <iostream> u

NOI题库 2704:寻找平面上的极大点

总时间限制: 1000ms 内存限制: 65536kB 描述 在一个平面上,如果有两个点(x,y),(a,b),如果说(x,y)支配了(a,b),这是指x>=a,y>=b;用图形来看就是(a,b)坐落在以(x,y)为右上角的一个无限的区域内.给定n个点的集合,一定存在若干个点,它们不会被集合中的任何一点所支配,这些点叫做极大值点.编程找出所有的极大点,按照x坐标由小到大,输出极大点的坐标.本题规定:n不超过100,并且不考虑点的坐标为负数的情况. 输入 输入包括两行,第一行是正整数n,表示是点

noi题库(noi.openjudge.cn) 1.8编程基础之多维数组T11——T20

T11 图像旋转 描述 输入一个n行m列的黑白图像,将它顺时针旋转90度后输出. 输入 第一行包含两个整数n和m,表示图像包含像素点的行数和列数.1 <= n <= 100,1 <= m <= 100.接下来n行,每行m个整数,表示图像的每个像素点灰度.相邻两个整数之间用单个空格隔开,每个元素均在0~255之间. 输出 m行,每行n个整数,为顺时针旋转90度后的图像.相邻两个整数之间用单个空格隔开. 样例输入 3 3 1 2 3 4 5 6 7 8 9 样例输出 7 4 1 8 5

Openjudge NOI题库 ch0111/05 派

总时间限制: 1000ms 内存限制: 65536kB 描述 我的生日要到了!根据习俗,我需要将一些派分给大家.我有N个不同口味.不同大小的派.有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成:可以是一整个派). 我的朋友们都特别小气,如果有人拿到更大的一块,就会开始抱怨.因此所有人拿到的派是同样大小的(但不需要是同样形状的),虽然这样有些派会被浪费,但总比搞砸整个派对好.当然,我也要给自己留一块,而这一块也要和其他人的同样大小. 请问我们每个人拿到的派最

Openjudge NOI题库 ch0111/01 查找最近的元素

总时间限制: 1000ms 内存限制: 65536kB 描述 在一个非降序列中,查找与给定值最接近的元素. 输入 第一行包含一个整数n,为非降序列长度.1 <= n <= 100000.第二行包含n个整数,为非降序列各元素.所有元素的大小均在0-1,000,000,000之间.第三行包含一个整数m,为要询问的给定值个数.1 <= m <= 10000.接下来m行,每行一个整数,为要询问最接近元素的给定值.所有给定值的大小均在0-1,000,000,000之间. 输出 m行,每行一个

Openjudge NOI题库 ch0111/07 和为给定数

总时间限制: 1000ms 内存限制: 65536kB 描述 给出若干个整数,询问其中是否有一对数的和等于给定的数. 输入 共三行:第一行是整数n(0 < n <= 100,000),表示有n个整数.第二行是n个整数.整数的范围是在0到10^8之间.第三行是一个整数m(0 <= m <= 2^30),表示需要得到的和. 输出 若存在和为m的数对,输出两个整数,小的在前,大的在后,中间用单个空格隔开.若有多个数对满足条件,选择数对中较小的数更小的.若找不到符合要求的数对,输出一行No