neuq周报

P4779 【模板】单源最短路径(标准版)

思路:图论,优先队列

#include <bits/stdc++.h>
using namespace std;
int n, m, s, ans[100005];
bool vis[100005];
struct node{
    int u, v;
    bool operator<(const node& d) const{
        return v > d.v;
    }
    bool operator>(const node& d) const{
        return v < d.v;
    }
};
vector<node> vec[100005];
priority_queue<node, vector<node> > q;
int main(){
    scanf("%d %d %d", &n, &m, &s);
    for(int i = 0; i < m; i++){
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        node d{b, c};
        vec[a].push_back(d);
    }
    for(int i = 1; i <= n; i++){
        ans[i] = 0x3f3f3f3f;
    }
    ans[s] = 0;
    node d{s, 0};
    q.push(d);
    while(!q.empty()){
        node cur = q.top();
        q.pop();
        if(vis[cur.u]) continue;
        vis[cur.u] = true;
        for(int i = 0; i < vec[cur.u].size(); i++){
            if(ans[vec[cur.u][i].u] > ans[cur.u] + vec[cur.u][i].v){
                ans[vec[cur.u][i].u] = ans[cur.u] + vec[cur.u][i].v;
                node tmp = {vec[cur.u][i].u, ans[vec[cur.u][i].u]};
                q.push(tmp);
            }
        }
    } 
    for(int i = 1; i <= n; i++){
        printf("%d ", ans[i]);
    }
    return 0;
}
B3647 【模板】Floyd

思路:最短路

#include <bits/stdc++.h>
#define inf  0x3f3f3f3f
using namespace std;
int Map[105][105];
int main()
{
    int n,m,u,v,w;
 
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            {
                if(i==j)
                    Map[i][j]=0;
                else
                    Map[i][j]=inf;
            }
 
    while(m--)
    {
        scanf("%d%d%d",&u,&v,&w);
        Map[u][v]=min(Map[u][v],w);
        Map[v][u]=Map[u][v]; 
    }
 
    int i,j,k;
 
    for(k=1;k<=n;k++)
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                if(Map[i][j]>Map[i][k]+Map[k][j])
                    Map[i][j]=Map[i][k]+Map[k][j];
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            printf("%d ",Map[i][j]);
        }
        printf("\n");
    }
 
    return 0;
}

P2661 [NOIP2015 提高组] 信息传递

思路:图论

#include <bits/stdc++.h>
using namespace std;
 
const int Max=200005;
int n,m,size,Index,cnt,tot,ans=1e9;
int num[Max],low[Max],sum[Max],p[Max<<1],vis[Max],first[Max]; 
struct shu{int to,next;};
shu edge[Max];
 
inline int get_int()
{
    int x=0,f=1;
    char c;
    for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
    if(c=='-') f=-1,c=getchar();
    for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    return x*f;
}
 
inline void build(int x,int y)
{
    edge[++size].next=first[x];
    first[x]=size;
    edge[size].to=y;
}
 
inline void tarjan(int point)
{
    num[point]=low[point]=++Index;
    p[++tot]=point,vis[point]=1;
    for(int u=first[point];u;u=edge[u].next)
    {
      int to=edge[u].to;
      if(!num[to]) tarjan(to),low[point]=min(low[point],low[to]);
      else if(vis[to]) low[point]=min(low[point],num[to]);
    }
    if(low[point]==num[point])
    {
      cnt++;
      while(1)
      {
          int x=p[tot--];
          sum[cnt]++;
          vis[x]=0;
          if(x==point) break;
      }
    }
}
 
int main()
{
    n=get_int();
    for(int i=1;i<=n;i++) build(i,get_int());
    for(int i=1;i<=n;i++) if(!num[i]) tarjan(i);
    for(int i=1;i<=cnt;i++) if(sum[i]!=1) ans=min(ans,sum[i]);
    cout<<ans<<"\n";
    return 0;
}

P1144 最短路计数

思路:图论

#include<bits/stdc++.h>
 
using namespace std;
const int MAXN=1e6+8;
int head[MAXN],num,s=1;
int n,m,dis[MAXN],cnt[MAXN]; 
struct edge
{
    int to,next;
}e[MAXN*2];
struct node
{
    int x,dis;
    bool operator<(node a)const
    {
        return dis>a.dis;
    } 
};
priority_queue<node> q; 
void add(int u,int v)
{
    e[++num].to=v;
    e[num].next=head[u];
    head[u]=num;
}
void dijkstra()
{
    memset(dis,0x3f3f3f3f,sizeof dis);
    dis[s]=0;
    q.push((node){s,0});
    cnt[1]=1;
    while(!q.empty())
    {
        int u=q.top().x;
        q.pop();
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+1)
            {
                dis[v]=dis[u]+1;
                q.push((node){v,dis[v]});
                cnt[v]=cnt[u]%100003;
            }
            else if(dis[v]==dis[u]+1)
            {
                cnt[v]=(cnt[u]+cnt[v])%100003;    
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1,u,v;i<=m;i++)
    {
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    dijkstra();
    for(int i=1;i<=n;i++)    cout<<cnt[i]<<endl;
    return 0;
}

P8794 [蓝桥杯 2022 国 A] 环境治理

思路:二分,最短路

#include<bits/stdc++.h>
using namespace std;
#define N 105
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define mid (l + r >> 1)
int n, Q, l, r, ans = INF;
int D[N][N], L[N][N], dis[N][N], reduce[N];
inline int check(int x) {
    int t = x / n, P = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) 
            dis[i][j] = INF;
    for (int i = 1; i <= n; i++) 
        dis[i][i] = 0;
    for (int i = 1; i <= n; i++)
        reduce[i] = t;
    for (int i = 1; i <= x - n * t; i++)
        ++reduce[i];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) 
            dis[i][j] = max(L[i][j], D[i][j] - reduce[i] - reduce[j]);//与每条道路都有的一个灰尘度的下限值比较取最小值
    for(int k=1;k<=n;k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) 
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            P += dis[i][j];
    if (P <= Q) return 1;
    else return 0;
}
 
signed main() {
    cin >> n >> Q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> D[i][j];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> L[i][j];
    l = 0, r = INF;
    while (l <= r) {
        if (check(mid)) ans = min(ans, mid), r = mid - 1;
        else l = mid + 1;
    }
    if (ans == INF) printf("-1");
    else printf("%lld", ans);
    return 0;
}

P3367 【模板】并查集

思路:并查集

#include<bits/stdc++.h>
using  namespace std;
const int MAXcount = 100000;
int par[MAXcount],height[MAXcount];
//par[i]表示i结点的父结点 “par[i]=-1”表示为根结点
//height[i]表示以i为根结点的树的结点个数
int Find(int x)//返回x的父亲结点
{
    int ini = x;
    while(1){
        if(par[x]==-1){
            //朴素
//            return x;
            break;
        }
        x=par[x];
    }
    //优化--路径压缩,再重复一次查找根结点操作,
    //每查找完一次父亲结点,
    //就将该结点的父亲par[]设置为该树的根结点
    //(也就是上一次循环查找到的x)
    while(1){
        if(par[ini]==-1){
            break;;
        }
        int zj = ini;
        ini=par[ini];
        par[zj]=x;
    }
    return x;
}
void Union(int x,int y)
{
    int rootx,rooty;
    rootx=Find(x);rooty=Find(y);
    if(rootx!=rooty){//如果根结点不同,进行合并操作
        //朴素--从x和y集合的根结点中随机选取一个作为另一个集合的根结点,完成合并操作
//        par[rooty]=par[rootx];
        //优化--选择树高小的合并到树高(集合的结点个数)大的根结点下
        if(height[rooty]>=height[rootx]){//如果y集合的结点数大于x集合的结点数,则将x集合合并到y结合的根结点下
            par[rootx]=rooty;
            height[rooty]+=height[rootx];//同时更新树高
        }else{
            par[rooty]=rootx;
            height[rootx]+=height[rooty];
        }
    }
}

int main()
{
    int N,M;
    memset(par,-1,sizeof(par));//初始化为-1,每个结点刚开始都是一个集合,所以其父结点为-1,表示其为根结点
    memset(height, 0, sizeof(height));//初始化数组为0
    cin>>N>>M;
    for(int i=0;i<M;i++){
        int z,x,y;
        cin>>z>>x>>y;
        if(z==1){
            Union(x,y);//合并集合x和y
        }else{
            int roox=Find(x);//查找x结点的父亲结点
            int rooy=Find(y);//查找y结点的父亲结点
            if(roox==rooy)cout<<"Y"<<endl;//比较两结点的父亲结点是否相同,可知是否在同一集合之中
            else cout<<"N"<<endl;
        }
    }
}
 

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

思路:图论

#include<iostream>
#include<vector>
#define int long long
 
using namespace std;
 
vector<int>edges[1010];//临接表存储图
vector<bool>visited(1010);//记录是否走过
vector<int>vexnum(1010);//记录每个点走过次数
int n, m, start, endd, ans = 0, sum = 0;
 
void dfs(int cur) {
    if (cur == endd) {
        sum++;//路径总数
        for (int i = 1; i <= n; i++) {
            if (visited[i]==1) {
                vexnum[i]++;//每个点走过次数
            }
        }
    }
    else {
        int len = edges[cur].size();
        for (int i = 0; i < len; i++) {
            int value = edges[cur][i];
            if (!visited[value]) {
                visited[value] = 1;
                dfs(value);
                visited[value] = 0;
            }
        }
    }
}
 
 
signed main()
{
    cin >> n >> m;
    int v1, v2, len;
    for (int i = 0; i < m; i++) {
        cin >> v1 >> v2;
        edges[v1].push_back(v2);
        edges[v2].push_back(v1);
    }
    cin >> start >> endd;
    visited[start] = 1;
    dfs(start);
    if (sum > 0) {
        for (int i = 1; i <= n; i++) {
            if (vexnum[i] == sum) {//是否存在点走过次数与路径总数相等的点
                ans++;//关键点计数
            }
        }
        cout << ans - 2 << endl;//减2是因为统计时多加了起点和终点
    }
    else {
        cout << "-1" << endl;
    }
    return 0;
}

P1330 封锁阳光大学

思路:图论

#include <bits/stdc++.h>
using namespace std;
const int maxv=1e4+10;
const int maxe=1e5+10;
 
inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}
 
struct node{
    int nxt,to;
}e[maxe<<1];
int tot=1,head[maxv];
int n,m,ans,sum[2];
bool vis[maxv],cor[maxv];
 
inline void add_edge(int from,int to){
    e[++tot]=node{head[from],to},head[from]=tot;
}
 
void read_and_parse(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int from=read(),to=read();
        add_edge(from,to),add_edge(to,from);
    }
}
 
bool dfs(int u,int c){
    if(vis[u])return cor[u]==c;
    vis[u]=1,++sum[cor[u]=c];
    for(int i=head[u];i;i=e[i].nxt)if(!dfs(e[i].to,c^1))return 0;
    return 1;
}
 
void solve(){
    for(int i=1;i<=n;i++)if(!cor[i]){
        sum[0]=sum[1]=0;
        if(!dfs(i,0)){puts("Impossible");return;}
        ans+=min(sum[0],sum[1]);
    }
    printf("%d\n",ans);
}
 
int main(){
    read_and_parse();
    solve();
    return 0;
}

P3916 图的遍历

思路:图论

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define  Max 100005
using namespace std;
vector<int > Graph[Max];
int flag[Max];
void  dfs(int v,int t);
int a[Max];
int main()
{
    int n,m,v1,v2;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>v1>>v2;
        Graph[v2].push_back(v1);
    }
    memset(flag, false, sizeof(flag));
    int v;
    for(int i=n;i;i--)
    {
        if(!flag[i])
        {
            dfs(i,i);
        }
    }
    for(int i=1;i<=n;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

void  dfs(int v,int t)
{
    flag[v]=true;
    a[v]=t; //遍历所有当前能达到的点
    for(int i=0;i<Graph[v].size();i++)
    {
        if(!flag[Graph[v][i]])
        {
            dfs(Graph[v][i],t);
        }
    }
}
 

P1119 灾后重建

思路:图论

#include <bits/stdc++.h>
using namespace std;
 
int M,N,Q;
int t[205];  //存储重建时间
int dist[205][205];  //存公路长度
 
 
void floyd(int k)   //以前k个村庄为中转点进行dp
{
    for(int i = 0; i < N; i ++)
    {
        for(int j = 0; j < N; j ++)
        {
            dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
        }
    }
    
    return;
}
 
int main()
{
    cin >> N >> M;  //村庄数和公路数
    for(int i = 0; i < N; i ++) cin >> t[i];
    
    for(int i = 0; i < N; i ++)
    {
        for(int j = 0 ;j < N; j ++)
        if(i != j)dist[i][j]=0x3f3f3f; //给两个村庄之间的边长初始化成无穷大
    }
    
    for(int i = 0; i < M; i ++) //用邻接矩阵来存边
    {
        int a,b,c;
        cin >> a >> b >> c;
        dist[a][b] = c;
        dist[b][a] = c;
    }
    
    cin >> Q;  //询问次数
    int temp = 0; //代表能访问到的序号最大的村庄
    for(int i = 1; i <= Q; i ++)
    {
        int a,b,c;
        cin >> a >> b >> c;
        while(temp < N && t[temp] <= c) //如果这天村庄已经重建好了,并且村庄序号没有越界
        {
            floyd(temp++);  //以前temp个村庄作为中转点
        }
        
        if(c < t[a] || c < t[b]) cout << -1;   //没重建好直接GG
        else if(dist[a][b] == 0x3f3f3f) cout << -1;  //两村庄不连通也直接GG
        else cout << dist[a][b];
        
        if(i != Q) cout << endl;
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值