NEUQ-ACM预备队必做题-7/8

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);

}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值