非精写版-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算法。
- Tarjan的本质是深搜。
for(int i=0;i<2*n;i++){ if(!dfn[i]) tarjan(i); }//深搜其它没有搜过的点
回溯阶段:low[u]=min(low[u],low[v]);
- 遇到强连通分量之前,时间戳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()自己(递归)有关系。
- 第一个人开始匹配,若匹配的第一个就正好无人选择就选择。
- 若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基础训练(终)的主要内容,如果未能解决你的问题,请参考以下文章