NEUQ-ACM预备队必做题-9

P3367 【模板】并查集

模板题,通过路径压缩解决。

#include <iostream>
using namespace std;

int n,m,a[10005];

int find (int f){
    if(a[f]==f){
        return f;
    }
    return a[f]=find(a[f]);
}

int main() {

    cin >> n >> m;
    for(int i=1;i<=n;i++){
        a[i]=i;
    }
    for(int i=0;i<m;i++){
        int x,y,z;
        cin >> z >> x >> y;
        if(z==1){
            a[find(x)]=find(y);
        }else{
            if(find(x)==find(y)){
                cout << 'Y'<<endl;
            }else{
                cout << 'N'<<endl;
            }
        }
    }
    
}

P8604 [蓝桥杯 2013 国 C] 危险系数

计算两点之间的路径数量,同时在通过一个节点时增加其被访问次数,如果访问次数与路径数量相等则该点为关键点。

#include <iostream>
using namespace std;

int map[1050][1050]={0},counts[1050]={0};
bool flags[1050];
int sum=0,ans=0,endU,endV,m,n;

void dfs(int s){
    if(s==endV){
        sum++;
        for(int i=1;i<=n;i++){
            if(flags[i]){
                counts[i]++;
            }
        }
        return;
    }
    for(int i=1;i<=n;i++){
        if(map[s][i]&&!flags[i]){
            flags[i]= true;
            dfs(i);
            flags[i]= false;
        }
    }

}

int main() {

    cin >> n >> m;

    for(int i=1;i<=m;i++){
        int u,v;
        cin >> u >> v;
        map[u][v]=1;
        map[v][u]=1;
    }

    cin >> endU >> endV;

    dfs(endU);

    for(int i=1;i<=n;i++){
        if(counts[i]==sum){
            ans++;
        }
    }
    cout << ans-1;
}

P1330 封锁阳光大学

可以理解为对图上的节点染色,相邻点颜色不同,统计两种颜色中数量更少的那一种颜色节点的数量即为河蟹数量,如果相邻节点颜色相同即无法完全封锁。

#include <iostream>
using namespace std;

struct Edge{
    int v, next;
}edge[200050];

int head[20050],cnt=0;
bool colored[20050]={0};
int colors[20050]={0};
int sum[2];

void addEdge(int tail,int front){
    cnt++;
    edge[cnt].v=front;
    edge[cnt].next = head[tail];
    head[tail]=cnt;
}

bool dfs(int node,int color){
    if(colored[node]){
        if(colors[node]==color){
            return true;
        }
        return false;
    }
    colored[node]= true;
    colors[node]=color;
    sum[color]++;
    bool flag=true;
    for(int i=head[node];i!=0&&flag;i=edge[i].next){
        flag=flag&&dfs(edge[i].v,1-color);
    }
    return flag;
}

int main(){
    int n,m;
    cin >> n >> m;
    for(int i=0;i<m;i++){
        int u,v;
        cin >> u >> v;
        addEdge(u,v);
        addEdge(v,u);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        if(colored[i]){
            continue;
        }
        sum[0]=sum[1]=0;
        if(!dfs(i,0)){
            cout << "Impossible";
            return 0;
        }else{
            if(sum[0]<sum[1]){
                ans+=sum[0];
            }else{
                ans+=sum[1];
            }
        }
    }
    cout << ans;
}

P3916 图的遍历

反向建图后DFS遍历图,从最大的节点开始逐个节点作为DFS起点,遇到的节点都将其end值设置为起点,如果end已经有值则不进行更新。

#include <iostream>
using namespace std;

struct Edge{
    int v,next;
}edge[200050];
int head[200050]={0};
int cnt=0;
int endV[200050]={0};

void addEdge(int in,int out){
    cnt++;
    edge[cnt].v=out;
    edge[cnt].next=head[in];
    head[in]=cnt;
}

int n,m;

void dfs(int s,int target){
    if(endV[s]){return;}
    endV[s]=target;
    for(int i=head[s];i;i=edge[i].next){
        dfs(edge[i].v,target);
    }
}

int main() {
    cin >> n >> m;
    for(int i=0;i<m;i++){
        int u,v;
        cin >> u >> v;
        addEdge(v,u);
    }
    for(int i=n;i;i--){
        dfs(i,i);
    }
    for(int i=1;i<=n;i++){
        cout << endV[i]<<' ';
    }
}

P1119 灾后重建

通过Floyd算法解决,但是并不是每一天都使用一次Floyd,由于t不下降,则可以在刚开始的时候,前边每有一个村庄修建完毕,就把他和他之前的所有村庄的Floyd矩阵求出,后方的村庄此时还没有建成,不需要更新。

#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f

int n,m,q;
int map[250][250],t[250];

void Floyd(int k){
    for(int i=0;i<n;i++)for(int j=0;j<n;j++){
        if(map[i][k]+map[k][j]<map[i][j]){
            map[i][j]=map[i][k]+map[k][j];
        }
    }
}

int main(){
    cin >> n >> m;
    for(int i=0;i<n;i++)for(int j=0;j<n;j++){
        if(i==j){map[i][j]=0;}
        else{map[i][j]=INF;}
    }
    for(int i=0;i<n;i++){
        cin >> t[i];
    }
    for(int i=0;i<m;i++){
        int u,v,w;
        cin >> u>>v>>w;
        map[u][v]=map[v][u]=w;
    }
    cin >> q;
    int index=0;
    for(int i=0;i<q;i++){
        int x,y,day;
        cin >> x >> y >> day;
        while(t[index]<=day&&index<n){
            Floyd(index);
            index++;
        }
        if(t[x]>day||t[y]>day||map[x][y]>=INF){
            cout << -1 << endl;
        }else{
            cout << map[x][y]<<endl;
        }
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值