贝壳找房魔法师顾问[并查集+DAG判断]

题目链接【https://nanti.jisuanke.com/t/27647】

//计蒜客2018复赛D题,想简单了。

题解:

  题目是中文的,不再赘述。

题解:

  分为三种情况:1、两个字符串都不能变:这种情况最简单,直接暴力判断两个支付穿是否相同即可。

         2、两个字符串都能变:把上下对应位置不同的点连无向边(因为都可以改变),建立了一个深林,这里用并查集实现,顺便维护每个联块的大小,对于每个联通块来说,要把这些点都变成一样的,最少要变换(size-1)次,即选出一个点,把其他的点都变成被选中的点。

         3、一个能变,一个不能变:这种情况最复杂。同第二种情况,这里需要建图,建立单向边,(只能由V变成C),对于每一个联通块,我们判断该联通块是不是DAG,如果是,那么只需要改变(size-1)次就行了。如果不是DAG,那么联通块中存在环,那么最少要变(size)次,只需要把这些点连接成有向环就可以了,保证了两两可以互达。

只是思路、具体细节和原因需要自己思考。欢迎斧正。QQ2421780543。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 15;
LL a[maxn], b[maxn];
char s[15], t[15];
//-----------------------并查集
int fa[maxn], val[maxn];
void init()
{
    for(int i = 1; i <= 100000; i++)
        fa[i] = i, val[i] = 1;
}
int Find(int u)
{
    if(fa[u] == u)
        return u;
    return fa[u] = Find(fa[u]);
}
void Unit(int u, int v)
{
    int x = Find(u);
    int y = Find(v);
    if(x != y)
    {
        fa[x] = y;
        val[y] += val[x];
        val[x] = 0;
    }
}
//-------------------------EDGE
int rd[maxn], vis[maxn], cnt = 0;;
vector<int>vt[maxn];
map<int, int>mp;
queue<int>que;
struct Edge
{
    int to, next;
    Edge(int to = 0, int next = 0): to(to), next(next) {}
} E[maxn * 4];
int head[maxn], tot;
void Init_Edge()
{
    for(int i = 1; i <= 100000; i++)
        head[i] = -1;
    tot = 0;
}
void Add_Edge(int u, int v)
{
    E[tot] = Edge(v, head[u]);
    head[u] = tot++;
}
//--------------------------主函数
int main ()
{
    int n, fg1 = 0, fg2 = 0;
    scanf("%d", &n);

    scanf("%s", s);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    scanf("%s", t);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &b[i]);

    if(s[0] == ‘V‘)
        fg1 = 1;
    if(t[0] == ‘V‘)
        fg2 = 1;

    if((!fg1) && (!fg2))//都不能更改
    {
        bool ans = true;
        for(int i = 1; i <= n && ans; i++)
            if(a[i] != b[i])
                ans = false;
        if(ans)
            printf("0\n");
        else
            printf("-1\n");
    }
    else if(fg1 && fg2)//都可以更改
    {
        init();
        for(int i = 1; i <= n; i++)
        {
            if(a[i] != b[i])
                Unit(a[i], b[i]);
        }
        int num = 0;
        for(int i = 1; i <= 100000; i++)
        {
            Find(i);
            if(fa[i] == i)
                num += val[i] - 1;
        }
        printf("%d\n", num);

    }
    else //只能改一个
    {
        init();
        Init_Edge();
        for(int i = 1; i <= n; i++)
            if(a[i] != b[i])
            {
                Unit(a[i], b[i]);
                Add_Edge(a[i], b[i]);
                rd[b[i]] ++;
                vis[a[i]] = vis[b[i]] = 1;
            }
        for(int i = 1; i <= 100000; i++)//提取联通块
        {
            if(vis[i])
            {
                int t = Find(i);
                if(mp[t])
                {
                    int tmp = mp[t];
                    vt[tmp].push_back(i);
                }
                else
                {
                    mp[t] = ++cnt;
                    vt[cnt].push_back(i);
                }
            }
        }
        int num = 0;
        for(int i = 1; i <= cnt; i++)//拓扑排序,判断DAG
        {
            int len = vt[i].size();
            for(int j = 0; j < len; j++)
            {
                int tmp = vt[i][j];
                if(rd[tmp] == 0)
                    que.push(tmp);
            }
            int tmp = 0;
            while(!que.empty())
            {
                int u = que.front();
                que.pop();
                tmp++;
                for(int j = head[u]; j != -1; j = E[j].next)
                {
                    int v = E[j].to;
                    rd[v]--;
                    if(rd[v] == 0)
                        que.push(v);
                }
            }
            if(tmp == len)
                num += len - 1;
            else
                num += len;
        }
        printf("%d\n", num);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/pealicx/p/9194750.html

时间: 2024-11-08 06:27:35

贝壳找房魔法师顾问[并查集+DAG判断]的相关文章

2018 计蒜之道复赛 贝壳找房魔法师顾问(并查集+dfs判环)

贝壳找房在遥远的传奇境外,找到了一个强大的魔法师顾问.他有 22 串数量相同的法力水晶,每个法力水晶可能有不同的颜色.为了方便起见,可以将每串法力水晶视为一个长度不大于 10^5105,字符集不大于 10^5105 的字符串.现在魔法师想要通过一系列魔法使得这两个字符串相同.每种魔法形如 (u,\ v),\ u,\ v \le 10^5(u, v), u, v≤105,可以将一个字符 uu改成一个字符 vv,并且可以使用无限次.出于种种原因,魔法师会强行指定这两个串能否进行修改. 若失败输出 -

贝壳找房魔法师顾问 2018 计蒜之道 复赛

https://nanti.jisuanke.com/t/A1725 V&V 无向图 强连通图 每个子图,n个点,选择n-1条,使互相连接 因为目标点x->点y,可以改为点y->点x V&C 弱连通图(将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图.如果一个有向图的基图是连通图,则有向图是弱连通图.) 1.一个弱连通子图,它里面的点与该弱连通子图外的点与没有关系,可以单独处理 2.弱连通子图里,一个点,必有另外点与之相邻,包括入和出 3.若弱连通子图里有环,则无论

并查集(1)-判断无向图是否存在环

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示.集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并. Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集合. Union:将两个子集合并成同一个集合. 其实判断一个图是否存在环已经有相应的算法,此文用并查集来判断一个图是否有环. 我们可以用一个一维数组parent[] 来记录子集合. 看下面这个图: 0 | | 1

HDU 3038 How Many Answers Are Wrong (带权并查集+区间判断)

题意:给你长度为n的区间,m个询问:a,b,c,问这m个问题有多少个是错误的(矛盾). 10 5 1 10 100 7 10 28 1 3 32 4 6 41 6 6 1 由6->6=1,  4->6=41 知4->5=40; 同理 由1->10=100,7->10=28 知1->7=72; 又由1->3=32,4-6=41 知1->7=73,与上面矛盾: 所以答案为1: #include<cstdio> #include<stdlib.h

HDU 1272 小希的迷宫(并查集,判断是否成环)

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 41583    Accepted Submission(s): 12822 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该

HDU-1272 小希的迷宫 (并查集、判断图是否为树)

Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房 间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走 了回头路).小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路.比如下面的例子,前两个是符合条件的,但是最后

HDU-1232 畅通工程 (并查集、判断图中树的棵数)

Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可).问最少还需要建设多少条道路? Input 测试输入包含若干测试用例.每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M:随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号.为简单起见,城镇从1到N编号. 注意

HDOJ1272(并查集,判断是否为树)

0 0 Yes 1 1 0 0 Yes 1 2 2 1 0 0 No //自回路不算一条边的! 居然有 0 0 这样的测试数据 #include<iostream> #include<cstdio> #include<cstring> #include<set> using namespace std; set<int> ans; set<int> member; const int SIZE=100000+16; int par[S

图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用

图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 B(G).其中 T(G)是遍历图时所经过的边的集合,B(G) 是遍历图时未经过的边的集合.显然,G1(V, T) 是图 G 的极小连通子图,即子图G1 是连通图 G 的生成树. 深度优先生成森林   右边的是深度优先生成森林: 连通图的生成树不一定是唯一的,不同的遍历图的方法得到不同的生成树;从不