一:挖地雷
首先观察数据范围 N <= 20 考虑暴搜
暴搜的几个必要组成
1.dfs函数的参数选择
2.搜索到结果时的判定
3.回溯
本题中,我们搜索记录的是可以挖到的地雷的数量,所以肯定有一个参数是记录地雷总数,然后需要知道我们当前是挖的哪一个地雷(因为我们可以从任意一个地雷开始挖)。由于最后需要输出最优答案的路径,所以这个需要一个临时数组来存放路径,那么就需要一个参数来记录这个临时数组的长度,也可以说是当前已经挖了多少个地雷。
代码:
/* */
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAX = 1e5+7,N = 25;
int g[N][N];//存连接图
int a[N];
int vis[N];
int n,num,ans;
int c[N];//需要输出路径时 额外定义的临时数组
int res[N];//答案数组 满足条件时将c重新复制一遍
void dfs(int x,int idx,int sum)
{
//当前访问的地窖编号 已经访问了几个地窖(c数组的长度) 地雷数
if(sum > ans)
{
//出现了更优解
ans = sum;
num = idx;//几个地窖
for(int i=0;i<idx;i++)
res[i] = c[i];
}
for(int i=1;i<=n;i++)
{
if(g[x][i] && !vis[i])
{
vis[i] = 1;
c[idx] = i;
dfs(i,idx+1,sum+a[i]);
vis[i] = 0;
}
}
return;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int x;
cin>>x;
g[i][j] = x;
}
}
// 可以从任何一个地雷开始挖 每一个点都搜索一下
for(int i=1;i<=n;i++)
{
vis[i] = 1;
c[0] = i;
dfs(i,1,a[i]);
vis[i] = 0;
}
for(int i=0;i<num;i++)cout<<res[i]<<" ";
cout<<endl<<ans;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);
cout.tie(0);
//cout<<fixed<<setprecision(2);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
二:P1434 滑雪
首先观察数据范围:在100以内 考虑剪枝和记忆化搜索
本题与上面题目类似 我们都可以从任何一个地方开始往下滑 所以我们从每一个点开始深搜记录最大值
记忆化搜索:既然我们从某一个点滑着滑着到了我之间已经(记录过的)从这个点开始往下滑的最大值了,就不需要再从他开始往下搜索了 记录值返回即可
搜索到没有满足条件的点时 说明他的周围已经没有比他还大的点了 那么只需要取他的周围点的最大值加1就是他的最大值 (回溯的时候更新值)
/* */
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAX = 1e5+7,N = 105;
int res[N][N];
int g[N][N];
int n,m,ans;
int dx[4] = {0,1,-1,0};
int dy[4] = {1,0,0,-1};
int dfs(int x,int y)
{
if(res[x][y])return res[x][y];//记忆化搜索
res[x][y] = 1;//默认初始 值为1
for(int i=0;i<4;i++)
{
int xx = x+dx[i];
int yy = y+dy[i];
if(xx>=1&&yy>=1&&xx<=n&&yy<=m&&g[xx][yy]>g[x][y])
{
dfs(xx,yy);
res[x][y] = max(res[x][y],res[xx][yy]+1);//回溯更新
}
}
return res[x][y];
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>g[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ans = max(ans,dfs(i,j));
}
}
cout<<ans;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);
cout.tie(0);
//cout<<fixed<<setprecision(2);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
三:P4017 最大食物链计数
有关食物链问题基本和拓扑排序有关 因为食物链中一般没有自环
观看此题:要找的是最左端是不会捕捉其他生物的生产者,最右端是不会被其他生物捕捉的最厉害的消费者,所以跟一个点的入度和出度有关 考虑拓扑排序 需要借助队列来实现
那么我们首先需要找到入度为0的点,让他入队 通过他去增加与他连接着的消费者的sum值,然后将那些与他连接着的点的入度-1,如果为0的话 让他也入队 让他当作新的起始点去更新他的消费者的sum值
/* */
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAX = 1e5+7,mod = 80112002,N = 5005;
vector<int>g[N];
queue<int>q;
int sum[N];
int in[N],out[N];
void topoSort()
{
while(!q.empty())
{
int t = q.front();
q.pop();
for(auto i : g[t])
{
in[i]--;
if(in[i] == 0)
q.push(i);
sum[i]=(sum[i]+sum[t])%mod;
}
}
}
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
in[y]++,out[x]++;
g[x].push_back(y);
}
for(int i=1;i<=n;i++)
{
if(in[i] == 0)
{
sum[i] = 1;
q.push(i);
}
}
topoSort();
int ans = 0;
for(int i=1;i<=n;i++)
{
if(out[i] == 0)
{
ans=(ans+sum[i])%mod;
}
}
cout<<ans%mod;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);
cout.tie(0);
//cout<<fixed<<setprecision(2);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
本人是个小白,希望佬们看了代码给些宝贵的建议~写的详细只是为了以后自己能看懂(●'◡'●)