Project Euler Problem 81-90

这篇博客详细解析了Project Euler 81至90的问题,包括路径和的不同情况,如两向、三向、四向路径,大富翁游戏的概率计算,长方形计数,长方体路径,素数幂三元组,积和数,罗马数字优化和立方体数字对。涉及动态规划、模拟和概率计算等方法。
摘要由CSDN通过智能技术生成

Project Euler Problem 81-90

Project Euler 81-90题解

Problem 81 Path sum: two ways

路径和:两个方向
在如下的5乘5矩阵中,从左上方到右下方始终只向右或向下移动的最小路径和为2427,由标注红色的路径给出。

131 673 234 103 18
201 96 342 965 150
630 803 746 422 111
537 699 497 121 956
805 732 524 37 331
在这个31K的文本文件matrix.txt(右击并选择“目标另存为……”)中包含了一个80乘80的矩阵,求出从该矩阵的左上方到右下方始终只向右和向下移动的最小路径和。

简单的动态规划

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;

typedef long long LL;
typedef long double LD;

const int MAXN=102;
const int INF= 1e9;

int m,n,T;
int data[MAXN][MAXN],dp[MAXN][MAXN],dpp[MAXN][MAXN];

int getN()
{
    char tmp;
    int n=0;
    do
    {
        tmp=getchar();
        if(tmp>='0'&&tmp<='9')
            n=n*10+int(tmp-'0');
    }while(tmp>='0'&&tmp<='9');
    //cout<<n<<" ";

    return n;
}

int main()
{
    freopen("p81in.txt","r",stdin);
    m=n=80;
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)
        {
            //scanf("%d",&data[i][j]);
            data[i][j]=getN();
            dp[i][j]=INF;
        }
    dp[0][0]=dpp[0][0]=data[0][0];       //init
    for(int i=1; i<m; i++) //init
        dp[i][0]=dpp[i][0]=dp[i-1][0]+data[i][0]; //init
    for(int j=1; j<n; j++)
    {
        for(int i=0; i<m; i++) //right
            dp[i][j]=dpp[i][j]=min(dp[i][j-1]+data[i][j],dp[i][j]);
        for(int i=1; i<m; i++) //down
            dp[i][j]=min(dp[i][j],dp[i-1][j]+data[i][j]);
        //for(int i=m-2; i>=0; i--) //up
          //  dpp[i][j]=min(dpp[i][j],dpp[i+1][j]+data[i][j]);
        for(int i=0; i<m; i++) //comebine
            dp[i][j]=dpp[i][j]=min(dp[i][j],dpp[i][j]);
    }
    printf("Answer: %d",dp[n-1][n-1]);
    return 0;
}


/**

131 673 234 103 18
201 96 342 965 150
630 803 746 422 111
537 699 497 121 965
805 732 524 37 331
**/

Problem 82 Path sum: three ways

路径和:三个方向

注意:这是第81题的一个更具挑战性的版本。

在如下的5乘5矩阵中,从最左栏任意一格出发,始终只向右、向上或向下移动,到最右栏任意一格结束的最小路径和为994,由标注红色的路径给出。

131 673 234 103 18
201 96 342 965 150
630 803 746 422 111
537 699 497 121 956
805 732 524 37 331

在这个31K的文本文件matrix.txt(右击并选择“目标另存为……”)中包含了一个80乘80的矩阵,求出从最左栏到最右栏的最小路径和。
动态规划

#include <algorithm>
#include <cstdio>
const int MAXN=102;
const int INF= 1e9;
int m,n,ans;
int data[MAXN][MAXN],dp[MAXN][MAXN],dpp[MAXN][MAXN];
int getN()
{
    char tmp;
    int n=0;
    do
    {
        tmp=getchar();
        if(tmp>='0'&&tmp<='9')
            n=n*10+int(tmp-'0');
    }
    while(tmp>='0'&&tmp<='9');
    return n;
}
int main()
{
    freopen("p82in.txt","r",stdin);
    m=n=80;
    ans=INF;
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)
        {
            data[i][j]=getN();
            dp[i][j]=INF;
        }
    for(int i=0; i<m; i++) //init
        dp[i][0]=dpp[i][0]=data[i][0]; //init
    for(int j=1; j<n; j++)
    {
        for(int i=0; i<m; i++) //right
            dp[i][j]=dpp[i][j]=min(dp[i][j-1]+data[i][j],dp[i][j]);
        for(int i=1; i<m; i++) //down
            dp[i][j]=min(dp[i][j],dp[i-1][j]+data[i][j]);
        for(int i=m-2; i>=0; i--) //up
            dpp[i][j]=min(dpp[i][j],dpp[i+1][j]+data[i][j]);
        for(int i=0; i<m; i++) //comebine
            dp[i][j]=dpp[i][j]=min(dp[i][j],dpp[i][j]);
    }
    for(int i=0; i<m; i++)
        if(ans>dp[i][n-1])
            ans=dp[i][n-1];
    printf("Answer: %d",ans);
    return 0;
}


/**

131 673 234 103 18
201 96 342 965 150
630 803 746 422 111
537 699 497 121 965
805 732 524 37 331
**/

Problem 83 Path sum: four ways

路径和:四个方向

注意:这是第81题的一个极具挑战性的版本。

在如下的5乘5矩阵中,从左上角到右下角任意地向上、向下、向左或向右移动的最小路径和为2297,由标注红色的路径给出。

131 673 234 103 18
201 96 342 965 150
630 803 746 422 111
537 699 497 121 956
805 732 524 37 331
在这个31K的文本文件matrix.txt(右击并选择“目标另存为……”)中包含了一个80乘80的矩阵,求出从左上角到右下角任意地向上、向下、向左或向右移动的最小路径和。

直接Dijkstra

#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
#define INF 1e9
int const limit=80;

int mat[limit][limit],cnt=0;
int dist[limit*limit+5];
bool done[limit*limit+5]= {
  0};
struct Edge
{
    int to,cost;
    bool operator < (const Edge & e) const
    {
        return this->cost>e.cost;
    }
    Edge(int t=0,int c=INF):to(t),cost(c) {}
} edges[limit*limit][4];
int getN()
{
    char tmp;
    int n=0;
    do
    {
        tmp=getchar();
        if(tmp>='0'&&tmp<='9')
            n=n*10+int(tmp-'0');
    }
    while(tmp>='0'&&tmp<='9');
    return n;
}

void addEdge(int x,int y,int i,int j)
{
    if(i>=limit||j>=limit||i<0||j<0) return ;
    edges[x*limit+y][cnt++]=Edge(i*limit+j,mat[i][j]);
}

void read()
{
    for(int i=0; i<limit; i++) /// read from txt
        for(int j=0; j<limit; j++)
            mat[i][j]=getN();
    ///build Graph
    for(int i=0; i<limit; i++)
        for(int j=0; j<limit; j++)
        {
            cnt=0;
            addEdge(i,j,i,j+1);
            addEdge(i,j,i,j-1);
            addEdge(i,j,i-1,j);
            addEdge(i,j,i+1,j);
        }
}

void dijkstra(int s=0)
{
    priority_queue<Edge> pque;
    for(int i=0; i<limit*limit; i++) dist[i]=INF;
    dist[s]=mat[0][0];
    pque.push(Edge(s,mat[0][0]));
    while(!pque.empty())
    {
        Edge x=pque.top();pque.pop();
        int u=x.to;
        if(done[u]) continue;
        done[u]=true;
        for(int i=0; i<4; i++)
        {
            Edge & e=edges[u][i];
            if(dist[e.to]>dist[u]+e.cost)
            {
                dist[e.to]=dist[u]+e.cost;
                pque.push(Edge(e.to,dist[e.to]));
            }
        }
    }
    cout<<dist[limit*limit-1]<<endl;
}
int main()
{
    freopen("p83in.t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值