落谷 2196 挖地雷

题面:

题目描述

在一个地图上有N个地窖(N<=20),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径。当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使某人能挖到最多的地雷。

输入输出格式

输入格式:

第1行只有一个数字,表示地窖的个数N。

第2行有N个数,分别表示每个地窖中的地雷个数。

第3行至第N+1行表示地窖之间的连接情况:

第3行有n-1个数(0或1),表示第一个地窖至第2个、第3个、…、第n个地窖有否路径连接。如第3行为1 1 0 0 0 … 0,则表示第1个地窖至第2个地窖有路径,至第3个地窖有路径,至第4个地窖、第5个、…、第n个地窖没有路径。

第4行有n-2个数,表示第二个地窖至第3个、第4个、…、第n个地窖有否路径连接。

… …

第n+1行有1个数,表示第n-1个地窖至第n个地窖有否路径连接。(为0表示没有路径,为1表示有路径)。

输出格式:

第一行表示挖得最多地雷时的挖地雷的顺序,各地窖序号间以一个空格分隔,不得有多余的空格。

第二行只有一个数,表示能挖到的最多地雷数。

输入输出样例

输入样例#1:

5
10 8 4 7 6
1 1 1 0
0 0 0
1 1
1

输出样例#1:

1 3 4 5
27

解题思路:

这个题乍一看是一个图论,其实可以用记忆化搜索(因为数据范围很小··)

但可以注意到这个挖地雷的过程有一个特点,那就是最后停止的地方一定是最后一个点。并且若一个点编号为 \(x\) ,使得 \(\forall s \in A ,A=\{1...x-1\}\) 不存在 \(x\) 到 \(s\) 的通路。那么就可以发现这个过程是符合动态规划的特点的,所以可以考虑用 \(dp\) 求解。

\(dp[i]\) 表示以 \(i\) 为起点所能挖到的地雷数量。状态更新的情况为: 若当前的点 \(a\) 到 \(b\) 点存在通路,那么就可以有 \(dp[b] = max(dp[b],dp[a]+w[b])\)

最后的答案就在所有情况更新完之后在 \(dp\) 数组中求一个 \(max\) 了。

这里还需要记录一下最大的值所在的下标 \(pos\) ,后面有用。

如何求路径 :

如何求路径是本题比较关键的一个点。对于记忆化搜索来说,比较容易处理,但对于 \(dp\) 来说就需要一些技巧了。

我们可以发现,之前求得的 \(ans-w[pos]\) 就是第二个点的时候所能挖的地雷数,和 \(dp\) 中进行比较看那个与上面算出来的值相等 且这两个点之间存在通路

最后拿一个数组记录就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=22;
typedef long long ll;
int g[maxn][maxn];
int w[maxn],road[maxn];
ll dp[maxn];
int main()
{
    ios::sync_with_stdio(false);
    //freopen("mine.in","r",stdin);
    int n;
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>w[i];
    for(int i=1;i<n;++i)
        for(int j=i+1;j<=n;++j)
            cin>>g[j][i];
    for(int i=1;i<=n;++i)
        dp[i]=w[i];
    for(int i=n;i>=1;--i){
        for(int j=i;j>=1;--j)
            if(g[i][j]){
                dp[j]=max(dp[j],dp[i]+w[j]);
            }
    }
    int cnt=1,now=0,pos=-1,ans;
    for(int i=1;i<=n;++i){
        if(now<dp[i]){
            now=dp[i];
            pos=i;
        }
    }
    ans=now;
    //求路径
    while(now>0)
    {
        now-=w[pos];
        road[cnt++]=pos;
        for(int i=1;i<=n;++i)
            if(now==dp[i]&&g[i][pos]){
                now=dp[i];
                pos=i;
            }
    }
    for(int i=1;i<cnt;++i)
        cout<<road[i]<<" ";
    cout<<endl;
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/SCaryon/p/9053962.html

时间: 2024-11-11 18:17:05

落谷 2196 挖地雷的相关文章

落谷P1872 回文串计数(回文树)

传送门 这道题显然可以用PAM做出来. PAM可以算出以字符串的第ii个字符为结尾的回文子串的个数.我们将其存到一个数组l[n],再求一个前缀和就可以把字符串的前i个字符的前缀有多少个回文子串求出来. 然后,我们将PAM清空,倒着做一遍,就可以求出以第i个字符为左端点的回文子串个数r[i].与它不相交的回文子串且在它前面的子串有l[i - 1]个,相乘再累加就是答案. 此题在落谷的评级是绿,那是因为此题数据范围只有2000,不用PAM也可以做.但此题可以当做PAM入门的练手题. #include

洛谷—— P2196 挖地雷

https://www.luogu.org/problem/show?pid=2196 题目背景 NOIp1996提高组第三题 题目描述 在一个地图上有N个地窖(N<=20),每个地窖中埋有一定数量的地雷.同时,给出地窖之间的连接路径.当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束.设计一个挖地雷的方案,使某人能挖到最多的地雷. 输入输出格式 输入格式: 输入文件mine.in有若干行. 第1行只有一个数字,表

洛谷——P2196 挖地雷

题目背景 NOIp1996提高组第三题 题目描述 在一个地图上有N个地窖(N<=20),每个地窖中埋有一定数量的地雷.同时,给出地窖之间的连接路径.当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束.设计一个挖地雷的方案,使某人能挖到最多的地雷. 输入输出格式 输入格式: 输入文件mine.in有若干行. 第1行只有一个数字,表示地窖的个数N. 第2行有N个数,分别表示每个地窖中的地雷个数. 第3行至第N+1行表示

落谷P1101 单词方阵 //参考代码

1 #include<iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 105; 6 char s[N][N], a[] = "yizhong"; 7 bool vis[N][N]; 8 int n; 9 int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1}, 10 dy[8] = {1, -1,

落谷P1101 单词方阵 //未完成

1 #include<iostream>/*cout<<endl; 2 for(int i=1;i<=n;i++) 3 for(int j=0;j<n;j++){ 4 5 cout<<a[i][j]; 6 if(j==n-1)cout<<endl; 7 }*/ 8 #include<cstring> 9 #include<cstdio> 10 using namespace std; 11 const int wd=101

AC日记——组合数问题 落谷 P2822 noip2016day2T1

题目描述 组合数表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法.根据组合数的定 义,我们可以给出计算组合数的一般公式: 其中n! = 1 × 2 × · · · × n 小葱想知道如果给定n,m和k,对于所有的0 <= i <= n,0 <= j <= min(i,m)有多少对 (i,j)满足是k的倍数. 输入输出格式 输入格式: 第一行有两个整数t,k,其中t代表该测试点总共有多少

落谷P3941 入阵曲

题目背景 pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv 丹青千秋酿,一醉解愁肠. 无悔少年枉,只愿壮志狂. 题目描述 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时候,觉得整个世界都焕然一新.这世界上怎么会有这么多奇妙的东西?曾经自己觉得难以 解决的问题,被一个又一个算法轻松解决. 小 F 当时暗自觉得,与自己的幼稚相比起来,还有好多要学习的呢. 一年过

落谷P1003 题解

题面 思路一:纯模拟.(暴力不是满分) 思路: 1.定义一个二维数组. 2.根据每个数据给二维数组赋值. 3.最后输出那个坐标的值. 思路二(正规思路): 逆序找,因为后来的地毯会覆盖之前的,一发现有解就输出 原文地址:https://www.cnblogs.com/kamimxr/p/11274467.html

落谷P1886 滑动窗口~

很好用的线性求变换区间最值的方法,比线段树快 用到了优先队列的算法 据说能用STL双向队列解但我不会QAQ #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; int n,k; int ans,l,r,a,b; int num[1000007]; int q[1000007],q