B3625 迷宫寻路
DFS问题,直接DFS遍历整个迷宫即可。
#include <iostream>
#include <stack>
using namespace std;
struct node{
int x,y;
};
int main() {
int n,m;
char map[105][105];
bool flag[105][105];
cin >> n>>m;
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
flag[i][j]= false;
if(i==0||j==0||i==n+1||j==m+1){
map[i][j]=='#';
continue;
}
cin >> map[i][j];
}
}
node q = {1,1};
flag[1][1]= true;
stack<node> S;
S.push(q);
while(!S.empty()){
node p = S.top();
S.pop();
if(p.x==n&&p.y==m){
cout <<"Yes";
return 0;
}
if(map[p.x-1][p.y]=='.'&&!flag[p.x-1][p.y]){
q = {p.x-1,p.y};
flag[p.x-1][p.y]=true;
S.push(q);
}
if(map[p.x+1][p.y]=='.'&&!flag[p.x+1][p.y]){
q = {p.x+1,p.y};
flag[p.x+1][p.y]=true;
S.push(q);
}
if(map[p.x][p.y-1]=='.'&&!flag[p.x][p.y-1]){
q = {p.x,p.y-1};
flag[p.x][p.y-1]=true;
S.push(q);
}
if(map[p.x][p.y+1]=='.'&&!flag[p.x][p.y+1]){
q = {p.x,p.y+1};
flag[p.x][p.y+1]=true;
S.push(q);
}
}
cout <<"No";
}
P1706 全排列问题
DFS问题,但是要注意DFS的回溯过程,需要将之前已经被访问过的数字的判断开关关闭。
#include <iostream>
using namespace std;
int n,flag[10],ans[10];
void dfs(int k){
if(k==n){
for(int i=1;i<=n;i++){
printf("%5d",ans[i]);
}
cout << endl;
}
for(int i=1;i<=n;i++){
if(!flag[i]){
flag[i]=true;
ans[k+1]=i;
dfs(k+1);
flag[i]=false;
}
}
}
int main() {
cin >> n;
for(int i=1;i<=n;i++){
flag[i]=false;
}
dfs(0);
}
P1451 求细胞数量
DFS问题,通过DFS判断连通分量即可。
#include <iostream>
using namespace std;
int n,m,map[105][105],flag[105][105];
void dfs(int x,int y){
if(map[x+1][y]!=0&&!flag[x+1][y]){
flag[x+1][y]=true;
dfs(x+1,y);
}
if(map[x-1][y]!=0&&!flag[x-1][y]){
flag[x-1][y]=true;
dfs(x-1,y);
}
if(map[x][y+1]!=0&&!flag[x][y+1]){
flag[x][y+1]=true;
dfs(x,y+1);
}
if(map[x][y-1]!=0&&!flag[x][y-1]){
flag[x][y-1]=true;
dfs(x,y-1);
}
}
int main() {
int count=0;
cin >> n >> m;
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
flag[i][j]=false;
if(i==0||i==n+1||j==0||j==m+1){
map[i][j]=0;
continue;
}
scanf("%1d",&map[i][j]);
}
}
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
if(map[i][j]!=0&&!flag[i][j]){
dfs(i,j);
count ++;
}
}
}
cout << count;
}
P1219 [USACO1.5] 八皇后 Checker Challenge
DFS问题,每次放棋子后都要将主副对角线及列开关打开,可以通过x+y和x-y+n的一维数组来存储对角线开关,回溯时将上次打开的开关关闭即可。
#include <iostream>
using namespace std;
int n;
int count =0;
int ans[15];
int flags[15]={0};
int diagFlags1[30]={0};
int diagFlags2[30]={0};
void dfs(int y){
if(y>n){
if(count >=3){
count ++;
return;
}
for(int i=1;i<=n;i++){
cout << ans[i]<<' ';
}
cout << endl;
count++;
return;
}
for(int i=1;i<=n;i++){
if(!flags[i]&&!diagFlags1[i-y+n]&&!diagFlags2[i+y]){
flags[i]=1;
diagFlags1[i-y+n]=1;
diagFlags2[i+y]=1;
ans[y]=i;
dfs(y+1);
flags[i]=0;
diagFlags1[i-y+n]=0;
diagFlags2[i+y]=0;
}
}
}
int main() {
cin >> n;
dfs(1);
cout << count;
}
B3647 【模板】Floyd
使用Floyd算法求图内所有节点到其它节点的最短路径。
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
int main() {
int n,m,dl[105][105];
cin >> n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j){
dl[i][j] =0;
}else{
dl[i][j] =INF;
}
}
}
for(int i=0;i<m;i++){
int u,v,w;
cin >> u >> v >> w;
dl[u-1][v-1] = w;
dl[v-1][u-1] = w;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
if(dl[j][i]+dl[i][k]<dl[j][k]||dl[k][i]+dl[i][j]<dl[k][j]){
dl[j][k]=dl[j][i]+dl[i][k];
dl[k][j]=dl[k][i]+dl[i][j];
}
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout << dl[i][j]<<' ';
}
cout << endl;
}
}
P4779 【模板】单源最短路径(标准版)
使用Dijkstra算法计算最短路径,但是这题的数据较大,需要用优先队列存点。
#include <iostream>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 100005
#define MAXM 200005
struct edge{
int to;
int dis;
int next;
};
struct priority{
long long ans;
int id;
bool operator <(const priority&x) const{
return x.ans<ans;
}
};
int head[MAXN]={0};
int cnt=0;
long long ans[MAXN];
bool flag[MAXN];
int m,n,s;
edge edges[MAXM];
void add_edge(int u,int v,int w){
edges[++cnt].to=v;
edges[cnt].dis = w;
edges[cnt].next=head[u];
head[u]=cnt;
}
priority_queue<priority> Q;
int main() {
cin >> n >> m >> s;
for(int i=1;i<=n;i++){
ans[i]=INF;
}
ans[s]=0;
for(int i=1;i<=m;i++){
int u,v,w;
cin >> u>>v>>w;
add_edge(u,v,w);
}
int u;
Q.push({0,s});
while(!Q.empty()){
priority temp = Q.top();
Q.pop();
u = temp.id;
if(!flag[u]){
flag[u]= true;
for(int i=head[u];i!=0;i=edges[i].next){
int v = edges[i].to;
if(ans[v]>ans[u]+edges[i].dis){
ans[v]=ans[u]+edges[i].dis;
if(!flag[v]){
Q.push({ans[v],v});
}
}
}
}
}
for(int i=1;i<=n;i++){
cout << ans[i]<<' ';
}
}
P2661 [NOIP2015 提高组] 信息传递
判断图中的最小环,通过并查集加计数计算每一个并查集的长度,取最短的并查集即可。
#include <iostream>
using namespace std;
int father[200005];
int get(int f,int &count){
count ++ ;
if(father[f]==f){
return f;
}else{
return get(father[f],count);
}
}
int main(){
int n,minCount=200005;
cin >> n;
for(int i=1;i<=n;i++){
father[i]=i;
}
for(int i=1;i<=n;i++){
int count =0;
int f;
cin >> f;
if(get(f,count)==i){
minCount=count<minCount?count:minCount;
}else{
father[i]=f;
}
}
cout << minCount;
}
P1144 最短路计数
同单源最短路径题,只不过每条路的权重都变为1,且为无向图,当有更小的长度时将计数覆盖,当长度相同时将计数相加。
#include <iostream>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 1000050
#define MAXM 2000050
struct edge{
int to;
int dis;
int next;
};
struct priority{
long long ans;
int id;
bool operator <(const priority&x) const{
return x.ans<ans;
}
};
int head[MAXN]={0};
int cnt=0;
long long ans[MAXN];
long long finalANS[MAXN];
int multi[MAXN];
bool flag[MAXN];
int m,n;
edge edges[MAXM];
void add_edge(int u,int v,int w){
edges[++cnt].to=v;
edges[cnt].dis = w;
edges[cnt].next=head[u];
head[u]=cnt;
}
priority_queue<priority> Q;
int main() {
cin >> n >> m;
for(int i=1;i<=n;i++){
multi[i]=1;
ans[i]=INF;
finalANS[i]=0;
}
finalANS[1]=1;
ans[1]=0;
for(int i=1;i<=m;i++){
int u,v;
cin >> u>>v;
add_edge(u,v,1);
add_edge(v,u,1);
}
int u;
Q.push({0,1});
while(!Q.empty()){
priority temp = Q.top();
Q.pop();
u = temp.id;
if(!flag[u]){
flag[u]= true;
for(int i=head[u];i!=0;i=edges[i].next){
int v = edges[i].to;
if(ans[v]>ans[u]+edges[i].dis){
ans[v]=ans[u]+edges[i].dis;
finalANS[v]=finalANS[u];
if(!flag[v]){
Q.push({ans[v],v});
}
}else if (ans[v]==ans[u]+edges[i].dis){
finalANS[v]+=finalANS[u];
finalANS[v]%=100003;
}
}
}
}
for(int i=1;i<=n;i++){
cout << finalANS[i]*multi[i]%100003<<endl;
}
}
P8794 [蓝桥杯 2022 国 A] 环境治理
仍旧是Floyd求最短路径,但是由于Floyd时间复杂度较长,需要使用二分来降低一次时间复杂度,将O(n^4)降至O(n^3*logMAXD*n)
#include <iostream>
using namespace std;
int map[105][105];
int least[105][105];
int n;
int min(int a,int b){
return a<b?a:b;
}
int sumForDay(int day){
int floyd[105][105],sum=0;
int i,j,k;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
floyd[i][j]=map[i][j];
}
}
for(i=0;i<n;i++){
int value = day/n+(day%n>=i+1?1:0);
for(j=0;j<n;j++){
floyd[i][j]-=value;
if(floyd[i][j]<least[i][j]){floyd[i][j]=least[i][j];}
floyd[j][i]-=value;
if(floyd[j][i]<least[j][i]){floyd[j][i]=least[j][i];}
}
}
for(k=0;k<n;k++){
for(i=0;i<n;i++){
for(j=0;j<n;j++){
floyd[i][j]=min(floyd[i][k]+floyd[k][j],floyd[i][j]);
}
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++){
sum+=floyd[i][j];
}
}
return sum;
}
signed main() {
int Q;
scanf("%d %d",&n,&Q);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&map[i][j]);
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&least[i][j]);
}
}
int left=0,right=100000*n,ans=-1;
while(left<=right){
int mid=(left+right)/2;
if(sumForDay(mid)<=Q){
right=mid-1;
ans=mid;
}else{
left=mid+1;
}
}
printf("%d",ans);
}