ACM学习笔记DAY4
今天学习的主要内容为DFS
首先是DFS的基本模板
然后最经典的最基础的DFS的运用:全排列问题
#include<iostream>
using namespace std;
int a[100];
int b[100];
int n;
void dfs(int x)
{
if (x == n + 1)
{
for (int i = 1; i <= n; i++)
{
cout << a[i] << " ";
}
cout << endl;
return;
}
for (int i = 1; i <= n; i++)
{
if (b[i] == 0)
{
a[x] = i;
b[i] = 1;
dfs(x + 1);
b[i] = 0;
}
}
return;
}
int main() {
cin >> n;
dfs(1);
}
下面的是关于图的一些基础知识以及一个基础的DFS
接下来是在今天没有ac的题目
第一题:
#include<stdio.h>
#include<string.h>
int n,k;
int cnt,sum;
char map[10][10];
int vis[10];
void dfs(int s){
if(cnt==k){
sum++;
return;
}
if(s>=n) return;
for(int i=0;i<n;i++){
if(map[s][i]=='#'&&!vis[i]){
vis[i]=1;
cnt++;
dfs(s+1);
cnt--;
vis[i]=0;
}
}
dfs(s+1);
}
int main(){
while(scanf("%d%d",&n,&k)&&n!=-1&&k!=-1){
cnt=sum=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++){
scanf("%s",map[i]);
}
dfs(0);
printf("%d\n",sum);
}
return 0;
}
第二题:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,t;
int ex,ey;
int s[10][10];
int vis[10][10];// 标记那些点不能走
int nex[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; // 四个方向
bool dfs(int x, int y, int tmp)
{
if(tmp > t)return false;
if(tmp != t && s[x][y] == 'D')return false;
if(tmp == t && s[x][y]=='D')return true;
if(tmp == t && s[x][y]!='D')return false; // 剪枝
int left = t - tmp; // 剩余的时间
int maxn = abs(ex-x) + abs(ey-y); // 剩余需要走的步数
if(left < maxn) return false; // 如果剩余的时间小于至少需要走的步数,那么剪枝
if(abs(maxn-left) %2 == 1)return false; // 根据奇偶行剪枝
for(int i=0; i<4; i++)
{
int xx = x + nex[i][0];
int yy = y + nex[i][1];
if(xx>=1 &&xx<=m && yy>=1 && yy <=n && vis[xx][yy]==0 && s[xx][yy]!='X')
{
vis[xx][yy] = 1;
if(dfs(xx,yy,tmp+1))return true;
vis[xx][yy] = 0;// 回溯
}
}
return false;
}
int main()
{
while(scanf("%d %d %d", &m,&n, &t)!= EOF)
{
if(m+n+t==0)break;
memset(vis, 0, sizeof(vis));
int x,y;
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
scanf(" %c", &s[i][j]);
if(s[i][j]=='S')
{
x=i; y=j;
}
if(s[i][j]=='D')
{
ex=i; ey=j;
}
}
}
vis[x][y] = 1; // 起点只能走一次,所以以后是不可能走起点了
if(dfs(x,y,0))cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
下面是最后一道题:
#include <iostream>
#include<cstdio>
#include <vector>
#include<limits.h>
using namespace std;
const int maxn = 105, INF = INT_MAX;
int K, N, R, visited[maxn] = { 0 };//钱币,城市,路线
int len = 0, minlen = INF, expense = 0;
int minvisited[maxn][10010];//表示到达节点v花费为cost的最短路径,用于剪枝
struct ROAD
{
int e, l, t;//终点,长度,花费
}r;
vector<ROAD>G[maxn];//100个城市
void DFS(int v)//如果参数设置为点,那么要在DFS子节点的时候做判断
{
if (v == N)//到达终点
{
if (len < minlen) minlen = len;//取最小值
return;
}
for (int j = 0; j < G[v].size(); j++)//DFS所有子节点
{
if (!visited[G[v][j].e])//子节点没有被访问
{
int cost = G[v][j].t + expense, length = G[v][j].l + len;
if (cost <= K && length < minlen && length < minvisited[G[v][j].e][cost])
{//剪枝:不超过总费用,长度小于最小总长度,长度小于到达某个点费用为cost的最小长度,DFS
visited[G[v][j].e] = 1;//标记为访问
len += G[v][j].l;//深度加一
expense += G[v][j].t;//钱币加上本条路径的费用
minvisited[G[v][j].e][cost] = length;
DFS(G[v][j].e);//DFS
len -= G[v][j].l;//恢复原状态
expense -= G[v][j].t;
visited[G[v][j].e] = 0;//恢复原状态
}
}
}
}
int main()
{
for (int i = 0; i < maxn; i++)
{
for (int j = 0; j < 10010; j++) minvisited[i][j] = INF;
}
cin >> K >> N >> R;
int s;
for (int i = 1; i <= R; i++)
{
scanf("%d%d%d%d", &s, &r.e, &r.l, &r.t);
G[s].push_back(r);
}//构图
visited[1] = 1;
DFS(1);
if (minlen != INF) cout << minlen << endl;
else cout << -1 << endl;
return 0;
}
-7.9 共勉