zoukankan      html  css  js  c++  java
  • 题解 P1407 【[国家集训队]稳定婚姻】

    这是蒟蒻的第三篇题解。

    这道题就是绿与被绿的故事。

    在读懂题以后,我们可以归纳出,如果这段姻缘是Unsafe的,那么这么几个人的关系必须是是个环。

    什么意思呢?

    以样例2为例:

    tijie1.png

    假设奇数的是 male ,偶数的是 female 。

    1 2 3 4分别代表 Melanie Ashley Scarlett Charles.

    那么在如图这个环中:原本的夫妻是12和34,但是由于他们在一个环中,说白了,就是在这个强连通分量中,他们可以任意更换对象。(狗血)

    样例1不必多说,(三角恋是不会有好结果的),因为这三个人没有构成强连通分量,所以婚姻安全了。(实际上就是把上图的1-4边断掉)

    所以就很明显,我们只需要建好图,然后运用 tarjan 求解强连通分量,如果一对夫妻在同一个强连通分量里面,那么婚姻就有危机了,否则就会风平浪静。

    然后又有一个问题了:怎么建图。

    原题读完后,很容易想到无向图,即建双边。

    但是!!!

    如果这样的话,我们上面所推导的一切全都前功尽弃了,因为无向图求强连通分量(==)想peach.强连通分量是针对有向图来说的。

    所以我们在建图时,要把夫妻和情侣都拆开建图。

    那怎么拆才能形成环呢?

    有三种方案:

    1. 男 -> 女
    2. 女 -> 男
    3. 男 -> 女 和 女 -> 男分开

    很显然,第一种和第二种是无论如何也不会出现环的。

    还是以样例2为例,如果按第1种方式建图,那么会是这样:

    tijie2.png

    这就很毒瘤。

    第2种同理。

    再看第三种:建图结果就像最上面我刚开始讲时用的那幅图。

    我再放一遍这个图:

    tijie1.png

    我是将夫妻间用 女 -> 男 存图,情侣间用 男 -> 女 存图。(内部含义自行理解 /kk)

    这样的话,就能通过女 -> 男 -> 女 -> 男来用算法找到环。

    对了,不会(tarjan)出门右转不谢。

    这道题实际上只要弄明白怎么建图,就是一道 tarjan 模板题

    讲了这么一大堆,下面是喜闻乐见的代码时间:

    #include<bits/stdc++.h>
    using namespace std;
    
    int cnt,n,tail,m,h[8005],dfn[8005],low[8005],id,tarn,bl[8005],x[8005],y[8005];
    bool vis[8005];
    stack<int> s;
    map<string,int> to;//map映射,将名字点映射成数字点 
    
    struct node {//链式前向星存图
    	int to,nxt;
    } b[25005];
    
    void add(int x,int y) {//加边操作 
    	b[++cnt].to=y;
    	b[cnt].nxt=h[x];
    	h[x]=cnt;
    }
    
    void tarjan(int u) {//tarjan算法求强联通分量 
    	s.push(u);
    	vis[u]=1;
    	dfn[u]=low[u]=++id;
    	for(int i=h[u]; i; i=b[i].nxt) {
    		int v=b[i].to;
    		if(!dfn[v]) {
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		} else {
    			if(vis[v]) {
    				low[u]=min(low[u],dfn[v]);
    			}
    		}
    	}
    	if(dfn[u]==low[u]) {
    		tarn++;
    		int v;
    		do {
    			v=s.top();
    			s.pop();
    			bl[v]=tarn;
    			vis[v]=0;
    		} while(u!=v);
    	}
    }
    
    int main() {
    	cin>>n;
    	string a,b;
    	for(int i=1; i<=n; i++) {
    		cin>>a>>b;
    		x[i]=to[a]=++tail;//将女方转换成数字
    		y[i]=to[b]=++tail;//将男方转换成数字
    		add(to[a],to[b]);//female -> male 存边
    	}
    	cin>>m;
    	for(int i=1; i<=m; i++) {
    		cin>>a>>b;
    		add(to[b],to[a]);//male -> female 存边
    	}
    	for(int i=1; i<=tail; i++) {
    		if(!dfn[i]) {
    			tarjan(i);
    		}
    	}
    	for(int i=1; i<=n; i++) {
    		if(bl[x[i]]==bl[y[i]]) {//bl 即 belong 表示当前这个点属于哪一个强连通分量 
    			puts("Unsafe");
    		} else {
    			puts("Safe");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    学习使用资源文件[4] 用资源中的图片做背景、使用 LoadFromResourceID
    WinAPI: ShellExecute 打开外部程序或文件
    学习使用资源文件[8] 关于 HInstance
    学习使用资源文件[3] 用 Image 显示资源中的图片
    薛定谔之猫_百度百科
    美国创业公司招聘工程师
    Two star programming
    vector 自定义排序
    Data Structures, Algorithms, & Applications in Java Suffix Trees
    Three Star Programmer
  • 原文地址:https://www.cnblogs.com/ahawzlc/p/12482162.html
Copyright © 2011-2022 走看看