2023NEUQACM Week8

必做题


B3647 【模板】Floyd

说是Floyd模板题,但我还是用了Dijkstra算法。
完整代码如下:

#include
using namespace std;
#define M 105
#define inf 0x7FFFFFFF
int n,m,u,v,w,Min,nex;
int Map[M][M];
int Dist[M];
bool vis[M];
int main()
{
    // freopen("D:\\test.txt","r",stdin);
    cin>>n>>m;
    for(int i=1 ; i<=n ; i++) fill(Map[i]+1,Map[i]+1+n,inf);
        // for(int j=1 ; j<=n ; j++) Map[i][j] = inf;
    for(int i=0 ; i>u>>v>>w;
        Map[u][v] =  min(Map[u][v],w);
        Map[v][u] = Map[u][v];
    }
    for(int s=1 ; s<=n ; s++){
        // for(int a=1 ; a<=n ; a++) vis[a]=1;
        fill(vis+1,vis+1+n,1);
        // for(int a=1 ; a<=n ; a++) Dist[a]=inf;
        fill(Dist+1,Dist+1+n,inf);
        int tmp = n;
        int start = s;
        Dist[start]=0;
        vis[start]=0;
        while(--tmp){
            Min = inf;
            for(int i=1 ; i<=n ; i++){
                if(Map[start][i]!=inf) 
                    Dist[i]=min(Dist[i],Dist[start]+Map[start][i]);
                if(vis[i] && Dist[i]

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

关键词:链式前向星、堆优化Dijkstra
思路:使用小根堆优化的 Dijkstra 算法(利用priority_queue)
对起始点的所有边都遍历一遍后,将成功以更近的方式到达目标点的情况记录下来,以目前从起始点到达各个终点的总距离由小到大的方式进行排序(入优先队列),其中最短的一条路径就是该终点的最短路径(数学证明略)。这样,我们每次都能确定一个点的最短距离,记录到 dij 数组里,然后再以这个点为起点(出队),遍历以它为起点的所有边(此时之前更长一些的路径还在队列里,要和它一起比较看谁更短),入队,我们就又能确定第二近的点及其总路程,如此往复,直到队列里没有点了,所有的最短路径就都找到了。
完整代码如下:

#include
using namespace std;
#define inf 0x7FFFFFFF
const int M = 2e5+5;
const int N = 1e5+5;
int n,m,s,u,v,w,nex,cnt=0;    
int dij[N],head[N];
bool vis[N];
struct edge{
    int to,nex,wei;
}e[M];
void add_edge(int ui, int vi, int wi)
{
    e[++cnt].to = vi; // 从编号1开始记录边,不初始化head(这样默认就是0),head[i]为0说明没有边了
    e[cnt].wei = wi;
    e[cnt].nex = head[ui];
    head[ui] = cnt;
}
struct node{
    int from,wei; // 记录起点,同一起点的按wei从小到大排序,这里的wei是到这个点时总共走的路程
    bool operator < (const node &x)const{ // 重载小于号,设置优先级(不要忘了大括号前的const)
        return x.wei < wei;
    }
}tmp;
priority_queue pq;
void dijkstra()
{
    dij[s]=0;
    pq.push((node){s,0});
    while(!pq.empty()){
        tmp = pq.top();
        pq.pop();
        if(vis[tmp.from]) continue;
        // tmp.from为起点的点已经看过了,队列后面的都不是tmp.from的最优解,直接删掉跳过
        vis[tmp.from] = true;
        for(int i=head[tmp.from] ; i ; i=e[i].nex){
            if(dij[e[i].to] > dij[tmp.from]+e[i].wei){
                dij[e[i].to] = dij[tmp.from]+e[i].wei;
                pq.push((node){e[i].to,dij[e[i].to]});
            }
        }
    }
}
int main()
{
    // freopen("D:\\test.txt","r",stdin);
    cin>>n>>m>>s;
    fill(dij+1,dij+1+n,inf);
    for(int i=0 ; i>u>>v>>w;
        add_edge(u,v,w);
    }
    dijkstra();
    for(int i=1 ; i<=n ; i++) cout << dij[i] << " ";
    return 0;
}

P2661 [NOIP2015 提高组] 信息传递

关键词:并查集、路径压缩
很不巧的是,我不会路径压缩,所以只能暴力求解
思路:如果两个点有公共的祖先,那么这两个点在相连后一定会形成一个环(因为每个点只会指向一个父节点),先初始化所有的点的祖先为自己,把各个点的父节点存到一个数组里,然后遍历每个点,当该点和其父节点不在同一个集合中时,将这个点的父节点设置为他的父节点;如果该点和其父节点在同一个集合中,我们从这个父节点一路向前找,一定能找到该子节点,记下路程。
本地跑不过,但是交上去能过……
完整代码如下:

#include
using namespace std;
#define inf 0x7FFFFFFF
const int N = 2e5+5;
int n,fp,cnt,fa[N],ans=inf;
int find(int k, int &cnt){
	++cnt;
	return k==fa[k] ? k : find(fa[k], cnt);
}
int main(){
    // freopen("D:\\test.txt","r",stdin);
	cin>>n;
	for(int i=1 ; i<=n ; i++) fa[i]=i;
	for(int i=1 ; i<=n ; i++){
		cin>>fp;
		cnt=0;
		i==find(fp,cnt) ? ans=min(ans,cnt) : fa[i]=fp;
	}			
	cout<

P1144 最短路计数

思路:使用堆优化 Dijkstra 算法,所有边的权重都是 1 1 1,开一个记录答案数量的数组 ans,当搜到一个点时,有三种情况:路程大于先前的,直接跳过;路程等于先前的, a n s + 1 ans+1 ans+1;路程小于先前的, a n s p r e = a n s n o w ans_{pre}=ans_{now} anspre=ansnow
完整代码如下:

#include
using namespace std;
#define inf 0x7FFFFFFF
#define mod 100003
const int N = 1e6+5;
const int M = 2e6+5;
int cnt=0,n,m,ui,vi;
int head[N],ans[N],dij[N];
bool vis[N];
struct edge{
    int to,nex;
}e[M];
struct node{
    int from,wei;
    bool operator < (const node &x)const{
        return x.wei < wei;
    }
}tmp;
void add_edge(int u,int v)
{
    e[++cnt].to = v;
    e[cnt].nex = head[u];
    head[u] = cnt;
}
priority_queue pq; // 队列存起点
void dijkstra()
{
    dij[1]=0;
    pq.push({1,0});
    while(!pq.empty()){
        tmp = pq.top();
        pq.pop();
        if(vis[tmp.from]) continue;
        vis[tmp.from] = true;
        for(int i=head[tmp.from] ; i ; i=e[i].nex){
            if(dij[e[i].to] > dij[tmp.from]+1){
                ans[e[i].to] = ans[tmp.from];
                dij[e[i].to] = dij[tmp.from]+1;
                pq.push({e[i].to,dij[e[i].to]});
            }
            else if(dij[e[i].to] == dij[tmp.from]+1){
                ans[e[i].to] += ans[tmp.from];
                ans[e[i].to] %= mod;
                // 这个点已经被push过了,不用再push了
            }
        }
    }    
}
int main()
{
    // freopen("D:\\test.txt","r",stdin);
    cin>>n>>m;
    fill(dij+1,dij+1+n,inf);
    ans[1]=1;
    for(int i=0 ; i>ui>>vi;
        add_edge(ui,vi);
        add_edge(vi,ui);
    }
    dijkstra();
    for(int i=1 ; i<=n ; i++) cout << ans[i] << '\n';
    return 0;
}

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

思路:二分查找治理天数(注意二分的上界,实测1e7能过),要优化一下治理的过程防止超时!
完整代码如下:

#include
using namespace std;
typedef vector v;
typedef vector> vv;
#define inf 0x7FFFFFFF
const int N = 105;
int n,Q;
bool vis[N];
vv Dust(N,v(N)), Lim(N,v(N));
int dijkstra(vv DustA)
{
    int nex,Min,P=0;
    v dij(N);
    for(int s=0 ; sQ) hdr = mid+1;
        else{
            mg = mid-1;
            ans = mid;
        }
    }
    return ans;
}
int main()
{
    // freopen("D:\\test.txt","r",stdin);
    scanf("%d%d",&n,&Q);
    for(int i=0 ; i

你可能感兴趣的:(NEUQACM,图论,算法)