非精写版-51nod基础训练(终)

Posted iuk11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非精写版-51nod基础训练(终)相关的知识,希望对你有一定的参考价值。

第一章

稳定婚姻

参考文章
首先介绍强连通分量:在有向图中,能形成回路的环。
在这里插入图片描述

红色部分为强连通分量。
在题目中,若夫妻离婚,男方要去找另一个女伴,然后迫使另一个女伴的夫妻双方离婚…过程描述为:男1->女2----男2->女3----男3->女4…男x->女1。
一定是兜兜转转一圈之后最后有一个离婚的男选了最初离婚的女1,这样大家都配好了对,又重新组合成了n对夫妻,那么就说婚姻不是稳定的关系。(若有一部分人重新配对,但是有一部分人未拆散,保持原状,也称为重新组合成了n对夫妻)
根据描述我们构建单项边,初始夫妻为女到男,之前有关系的为男到女。
根据tarjan算法,得出所有的强连通分量,若一对夫妻在同一强连通分量中,则不稳定(不安全)。
在这里插入图片描述
如图,男1-女1的婚姻在强连通分量中,不稳定;男2-女2的婚姻同理,不稳定;男3-女3则不在强连通分量中,稳定。
懂了概念,怎么实现tarjan算法。

  1. Tarjan的本质是深搜。
    在这里插入图片描述
    在这里插入图片描述
    for(int i=0;i<2*n;i++){ if(!dfn[i]) tarjan(i); }//深搜其它没有搜过的点
    回溯阶段:low[u]=min(low[u],low[v]);
  2. 遇到强连通分量之前,时间戳dfn[]与low[]相安无事。
    low[i]是记录i点属于哪个强连通分量,若无环,自己就是一个强连通分量。
    dfn[i]则是记录i点进入搜索后是第几个被搜索的点,也就是时间戳。
    相安无事阶段:

    遇到了之前访问过的点(表示成环了):
    在这里插入图片描述

回溯阶段:low[u]=min(low[u],dfn[v]);

完整代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
char a[10],b[10];
map<string,int> mp;
vector<int> g[maxn];
int dfn[maxn],low[maxn],s[maxn],scc[maxn];
int top,cnt,num;
void tarjan(int u){
	s[++top]=u;
	dfn[u]=low[u]=++num;
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}else if(!scc[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]){
		++cnt;
		while(true){
			int v=s[top--];
			scc[v]=cnt;
			if(u==v) break;
		}
	}
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		scanf("%s %s",a,b);
		mp[a]=2*i;
		mp[b]=2*i+1;
		g[2*i].push_back(2*i+1);
	}
	int m;
	cin>>m;
	for(int i=1;i<=m;i++){
		scanf("%s %s",a,b);
		g[mp[b]].push_back(mp[a]);
	}
	for(int i=0;i<2*n;i++){
		if(!dfn[i]) tarjan(i);
	}
	for(int i=0;i<n;i++){
		if(scc[i*2]==scc[i*2+1]) printf("Unsafe\\n");
		else printf("Safe\\n");
	}
	//system("pause");
	return 0;
}

飞行员配对(二分图最大匹配)

匈牙利算法

参考文章
二分图的理解,在这道题中可以把英国飞行员当成左边的部分,外籍飞行员当成右边的部分。左边的点会对应右边的一些点,如图(示例的图):
在这里插入图片描述
从左边第一个人开始,进入函数find(),记住是==每个人的vis[]在进去前都初始化一次。==这样vis[]记录是否访问过右边的某个人,只对find()调用find()自己(递归)有关系。

  1. 第一个人开始匹配,若匹配的第一个就正好无人选择就选择。
  2. 若x匹配到的第一个人已经被别人y选走了,就找到那个人y,看看y还有没有其它可以选择的人,然后把当前的空位让出来给x。若y没有可以匹配的人,就不让出空位。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=105;
int maps[maxn][maxn];
int vis[maxn<<1];
int lac[maxn],sum,m,n,a,b;
bool find(int x){
	for(int j=m+1;j<=n;j++){
		if(maps[x][j]&&!vis[j]){
			vis[j]=1;
			if(!lac[j]||find(lac[j])){
				lac[j]=x;
				return true;
			}
		}
	}
	return false;
}
int main(){
	scanf("%d%d",&m,&n);
	while(scanf("%d%d",&a,&b)){
		if(a==-1&&b==-1) break;
		maps[a][b]=1;
	}
	for(int i=1;i<=m;i++){
		memset(vis,0,sizeof(vis));
		if(find(i)){
			sum++;
		}
	}
	for(int i=m+1;i<=n;i++){
		cout<<i<<" "<<lac[i]<<endl;
	}
	if(!sum) printf("No Solution\\n");
	else printf("%d\\n",sum);
	//system("pause");
	return 0;
}
网络流

网络流看了一下不能理解到,等省赛结束之后在开始学习了。先鸽了。

后记

在这里插入图片描述
从最初萌生写完这个基础专题的念头,还是有点完美主义,本来可以只写一部分的,有些也没必要写或者很花费时间的题。
现在状态正好,希望过几天不会变差。还是不会dp,下一步该去尝试学dp的知识了,也就是因为对dp不敏感吧,蓝桥杯国赛被虐惨了。
希望自己可以过几天有个好成绩吧,怕自己flag砸了,我还把签名改了,不敢说省金了。最后几天刷完往届的题,只是刷题就好了,什么也别想了,没有期待,没有不甘心,没有沮丧,没有莫名自信,只要刷题就好了。

以上是关于非精写版-51nod基础训练(终)的主要内容,如果未能解决你的问题,请参考以下文章

非精写版-51nod基础训练

非精写版-51nod基础训练

非精写版-51nod基础训练

非精写版-51nod基础训练(持续更新)

*51nod - 1459迷宫游戏(记录双向权值的Dijkstra单源最短路)

51nod_1459 最短路 dijkstra 特调参数