【Atcoder - AGC027C】ABland Yard

版权声明:本文为博主原创文章……懂吗?要尊重别人的劳动成果呐 https://blog.csdn.net/Tiw_Air_Op1721/article/details/82718569

@ABland Yard@


@题目描述 - English@

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 900 points

Problem Statement
You are given an undirected graph consisting of N vertices and M edges.The vertices are numbered 1 to N, and the edges are numbered 1 to M. In addition, each vertex has a label, A or B. The label of Vertex i is si. Edge i bidirectionally connects vertex ai and bi.

The phantom thief Nusook likes to choose some vertex as the startpoint and traverse an edge zero or more times. Today, he will make a string after traveling as above, by placing the labels of the visited vertices in the order visited, beginning from the startpoint.

For example, in a graph where Vertex 1 has the label A and Vertex 2 has the label B, if Nusook travels along the path 1→2→1→2→2, the resulting string is ABABB.

Determine if Nusook can make all strings consisting of A and B.

Constraints
2≤N≤2×10^5, 1≤M≤2×10^5
|s|=N, si is A or B.
1≤ai,bi≤N
The given graph may NOT be simple or connected.

Input
Input is given from Standard Input in the following format:
N M
s
a1 b1
……
aM bM

Output
If Nusook can make all strings consisting of A and B, print Yes; otherwise, print No.

Sample Input 1
2 3
AB
1 1
1 2
2 2
Sample Output 1
Yes

Since Nusook can visit Vertex 1 and Vertex 2 in any way he likes, he can make all strings consisting of A and B.
题目描述图1

Sample Input 2
4 3
ABAB
1 2
2 3
3 1
Sample Output 2
No

For example, Nusook cannot make BB.
The given graph may not be connected.
题目描述图2

Sample Input 3
13 23
ABAAAABBBBAAB
7 1
10 6
1 11
2 10
2 8
2 11
11 12
8 3
7 12
11 2
13 13
11 9
4 1
9 7
9 6
8 13
8 6
4 10
8 7
4 3
2 1
8 12
6 9
Sample Output 3
Yes

Sample Input 4
13 17
BBABBBAABABBA
7 1
7 9
11 12
3 9
11 9
2 1
11 5
12 11
10 8
1 11
1 8
7 7
9 10
8 8
8 12
6 2
13 11
Sample Output 4
No

@中文题意@

n点m边的图(可自环可重边),给每个点附上权值’A’或’B’。一条路径(可经过重复边)的权值为从起点到终点的所有点的权值相连成的字符串。

问是否对于任意一个由‘A’, ‘B’组成的串,都存在一条路径的权值等于它。

@分析@

【结论题嘛……我也不太好说】
先说对于自环。我们可以把一个结点拆成两个结点,这两个结点与其他结点的连边情况是一模一样的。然后,假如这个点有一个自环,则连通这两个结点。可以发现这个拆点后的图与原图是等价的。

假设某一个串中有一个A,且它前后都为B。则我们可以由一个B结点出发,走到任意一个相邻的A结点,再走回B结点,以构造串中这个单独的A。

假设某一个串中有x个连续的A(x>2),且它前后都为B。则我们可以由一个B结点出发,走到一个相邻的A结点,再从这个A结点出发走一个全部都由A结点组成的、长度为(x-1)的环,回到这个A结点,并回到它之前的B结点,以构造串中连续的A。

但是——假设某一个串中有两个连续的A(x>2),且它前后都为B。不管图长什么样子,我们都不能按照上面的方式来做(注意没有自环)。

上面的例子即是对于“AABBAABB……”型的无限长串,我们必须针对它进行构造。

@结论@

如果有一个形如AABBAABBAABB……型的环,则答案为Yes
【这个结论……说实话我是猜出来的】
【2018/9/16 UPD:官方题解也没说为什么……还真TM是结论题】

我们这样进行转换:
如果一条边连接的两个点点权相同,则边权为1;否则边权为0。问题等价于:是否存在一个环,环上的边权是形如10101010101一样交替出现的。
再转换:我们再拆点,将a拆成a1与a2。a1表示入边边权为0,出边边权为1的点;a2表示入边边权为1,出边边权为0的点。于是在新图里面出现的环就等价于原图的101010101环。
这样,只需要再拓扑排序判断图中是否存在环即可。

@代码@

……我估计你们也是看不懂代码的。
不过还是支持询问啦,有什么不解我尽力回答qwq

#include<cstdio>
#include<queue>
using namespace std;
const int MAXN = 200000;
const int MAXM = 2000000;
struct edge{
    int to;
    edge *nxt;
}edges[MAXM + 5], *adj[4*MAXN + 5], *ecnt = &edges[0];
char s[MAXN + 5];
void addedge(int u, int v) {
    edge *p = (++ecnt);
    p->to = v, p->nxt = adj[u], adj[u] = p;
}
int indeg[4*MAXN + 5];
int main() {
    int N, M;
    scanf("%d%d", &N, &M);
    scanf("%s", s+1);
    for(int i=1;i<=M;i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        if( a == b ) {
            addedge(a+N, a+2*N);
            addedge(a+3*N, a);
        }
        else {
            if( s[a] == s[b] ) {
                addedge(a+N, b);
                addedge(b+N, a);
                addedge(a+3*N, b);
                addedge(b+N, a+2*N);
                addedge(b+3*N, a);
                addedge(a+N, b+2*N);
                addedge(a+3*N, b+2*N);
                addedge(b+3*N, a+2*N);
            }
            else {
                addedge(a, b+N);
                addedge(b, a+N);
                addedge(a+2*N, b+N);
                addedge(b, a+3*N);
                addedge(b+2*N, a+N);
                addedge(a+2*N, b+N);
                addedge(a+2*N, b+3*N);
                addedge(b+2*N, a+3*N);
            }
        }
    }
    for(int i=1;i<=4*N;i++) {
        for(edge *p=adj[i];p!=NULL;p=p->nxt)
            indeg[p->to]++;
    }
    queue<int>que;
    for(int i=1;i<=4*N;i++)
        if( !indeg[i] ) que.push(i);
    int cnt = 0;
    while( !que.empty() ) {
        cnt++;
        int f = que.front(); que.pop();
        for(edge *p=adj[f];p!=NULL;p=p->nxt) {
            indeg[p->to]--;
            if( !indeg[p->to] ) que.push(p->to);
        }
    }
    if( cnt == 4*N ) puts("No");
    else puts("Yes");
}

@END@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

猜你喜欢

转载自blog.csdn.net/Tiw_Air_Op1721/article/details/82718569
今日推荐