NEUQ-ACM预备队必做题——第八周、第九周

洛谷B3647 【模板】Floyd

思路:

floyd的板子题

代码:

#include <iostream>
#include <cstring>
using namespace std;
const int N = 110;

int dist[N][N], n, m;

void floyd()
{
    for (int k = 1; k <= n; k ++)
	    for (int i = 1; i <= n; i ++)
	    {
		    for (int j = 1; j <= n; j ++)
		    {
			for (int k = 1; k <= n; k ++)
				dist[j][i] = min (dist[j][i], dist[j][k] + dist[k][i]);
		    }
	    }
}

int main()
{
	cin >> n >> m;
	
	memset(dist, 0x3f, sizeof dist);
	
	for (int i = 1; i <= n; i ++ )
	{
		dist[i][i] = 0;
	}
	
	while(m--)
	{
		int u, v, w;
		cin >> u >> v >> w;
		dist[u][v] = dist[v][u] = min(dist[v][u], w);
	}
	
	floyd();
	
	for (int i = 1; i <= n; i ++)
	{
		for (int j = 1; j <= n; j ++)
		{
			cout << dist[i][j] << ' ';
		}
		puts("");
	}
	
	return 0;
}

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

思路:

dijkstra的板子题,我背的这个板子有点问题,只能过两个样例。(过段时间再补吧)

代码:

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
typedef pair<int,int>PII;
const int N=150000;
bool st[N];
int dist[N],w[N];
int e[N],ne[N],h[N],idx;
int n,m,s;
void add(int a,int b,int c)
{
    w[idx]=c;
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dijkstra()
{
    dist[1]=0;
    priority_queue<PII,vector<PII>,greater<PII>>heap;
    heap.push({0,1});

    while(heap.size())
    {
        PII t=heap.top();
        heap.pop();
        int ver=t.second,distance=t.first;
        if(st[ver])continue;
        st[ver]=true;

        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>distance+w[i])
            {
                dist[j]=distance+w[i];
                heap.push({dist[j],j});
            }
        }
    }
}
int main()
{
    memset(dist,0x3f,sizeof dist);
    memset(h,-1,sizeof h);
    cin>>n>>m>>s;
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }
    dijkstra();
    for(int i = 1; i <= n; i ++)
    {
    	cout << dist[i] << ' ';
	}
    return 0;
}

洛谷P2661 [NOIP2015 提高组] 信息传递

思路:

并查集求最小环

代码:

#include<cstdio>
#include<iostream>
using namespace std;
const int N = 2e5+10;
int f[N],d[N],n,minn,last;   
int fa(int x)
{
    if (f[x]!=x)                       
    {
        int last=f[x];                 
        f[x]=fa(f[x]);                 
        d[x]+=d[last];                 
    }
    return f[x];
}
void check(int a,int b)
{
    int x=fa(a),y=fa(b);               
    if (x!=y) {f[x]=y; d[a]=d[b]+1;}   
    else minn=min(minn,d[a]+d[b]+1);   
    return;
}
int main()
{
    int i,t;
    scanf("%d",&n);
    for (i=1;i<=n;i++) f[i]=i;         
    minn=0x3f3f3f3f;
    for (i=1;i<=n;i++)
    {
        scanf("%d",&t);
        check(i,t);                    
    }
    printf("%d",minn);
    return 0;
}

洛谷

思路:

spfa的板子题

代码:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=1e6+10,maxm=2e6+10,INF=0x3f3f3f3f,MOD=100003;
vector<int>G[maxn];int dep[maxn];bool vis[maxn];int cnt[maxn];

int main(){
    int N,M;scanf("%d%d",&N,&M);
    for(int i=1;i<=M;i++){
        int x,y;scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    queue<int>Q;dep[1]=0;vis[1]=1;Q.push(1);cnt[1]=1;
    while(!Q.empty()){
        int x=Q.front();Q.pop();
        for(int i=0;i<G[x].size();i++){
            int t=G[x][i];
            if(!vis[t]){vis[t]=1;dep[t]=dep[x]+1;Q.push(t);}
            if(dep[t]==dep[x]+1){cnt[t]=(cnt[t]+cnt[x])%MOD;}
        }
    }
    for(int i=1;i<=N;i++){
        printf("%d\n",cnt[i]);
    }
    return 0;
}

洛谷P3367 【模板】并查集

思路:

模板题😬

代码:

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

int p[N];
int n, m;

int find(int x)
{
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}

int main()
{
	cin >> n >> m;
	
	for (int i = 1; i <= n; i ++) p[i] = i;
	
	while(m--)
	{
		int z, x, y;
		cin >> z >> x >> y;
		x = find(x);
		y = find(y);
		if (z == 1)
		{
			p[x] = y;
		}
		else 
		{
			if (x != y) puts("N");
			else puts("Y");
		}
	}
	return 0;
}

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

思路:

dfs搜索,先求出几条路径,在求出每一条路径的时候,经过点都记录一下,最后比较路径数与经过点的次数,如果一样则说明这个点是关键点。

代码:

#include <iostream>
using namespace std;
const int N = 1010;

int g[N][N], cnt[N];
bool st[N*2];
int n, m, start, ed, sum;

void dfs(int u)
{
	if (u == ed)
	{
		sum ++;
		for (int i = 1; i <= n; i++)
			if (st[i]) cnt [i]++;
		return ;
	}
	
	for (int i = 1; i <= n; i ++)
	{
		if(g[i][u] == 1 && !st[i])
		{
			st[i] = true;
			dfs(i);
			st[i] = false;
		}
	}
	return ;
}

int main()
{
	cin >> n >> m;
	for(int i = 1; i <= m; i ++)
	{
		int a, b;
		cin >> a >> b;
		g[a][b] = g[b][a] = 1;
	}
	
	cin >> start >> ed;
	
	dfs(start);
	
	if(sum > 0)
	{
		int res = 0;
		for (int i = 1; i <= n; i ++)
		{
			if(cnt[i] == sum) res ++;
		}
		cout << res - 1;
	}
	else cout << -1;
	
	return 0;
}

洛谷P1330 封锁阳光大学

思路:

用的染色法,但是只过了6个样例,代码并不完美,仍需完善。

代码:

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;

int e[N], ne[N], h[N], idx;
int color[N], n, m, sum[10], ans;
bool st[N];

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

bool dfs(int u, int c)
{
	color[u] = c;
	sum[c] ++;
	
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		
		if (!color[j])
		{
			if(!dfs(j, 3-c)) return false;
		}
		else if (color[j] == c) return false;
	}
	return true;
}

int main()
{
	cin >> n >> m;
	
	memset(h, -1, sizeof h);
	
	while(m --)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
		add(b, a);
	}
	
	int flag = true;
	for (int i = 1; i <= n; i++)
	{
		if(!color[i])
		{
			if(!dfs(i, 1))
			{
				flag = false;
				break;
			}
		}
		ans += min(sum[1], sum[2]);
		sum [1] = sum[2] = 0;
	}
	if(!flag) puts("impossible");
	else cout << ans;
	
	return 0;
}


洛谷P3916 图的遍历

思路:

一开始以为就是爆搜每个点能够到达的最大点,但是时间复杂度太高了,看了题解,学会了新的知识——反向建图。

代码:

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;

int e[N], ne[N], h[N], idx;
int n, m, ans[N];
bool st[N];

void add(int b, int a)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u, int a)
{
	if(ans[u]) return ;
	ans[u] = a;
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if(!st[j])
		{
			st[j] = true;
			dfs(j, a);
			st[j] = false;
		}
	}
}

int main()
{
	cin >> n >> m;
	
	memset(h, -1, sizeof h);
	
	while(m--)
	{
		int a, b;
		cin >> a >> b;
		add(a, b);
	}
	
	for (int i = n; i > 0; i --)
	{
		if(!ans[i]) dfs(i, i);
	}
	
	for (int i = 1; i <= n; i ++)
		cout << ans[i] << ' ';
		
	return 0;
}

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值