1. 程式人生 > >CF623A Graph and String 【題解】

CF623A Graph and String 【題解】

題目描述

One day student Vasya was sitting on a lecture and mentioned a string s 1 s 2 . .

.   s n s_{1}s_{2}...\ s_{n} , consisting of letters “a”, “b” and “c” that was written on his desk. As the lecture was boring, Vasya decided to complete the picture by composing a graph G with the following properties:

  • G has exactly n vertices, numbered from 1 to n .
  • For all pairs of vertices i and j , where i≠j , there is an edge connecting them if and only if characters s i s_{i}
    and s j s_{j} are either equal or neighbouring in the alphabet. That is, letters in pairs “a”-“b” and “b”-“c” are neighbouring, while letters “a”-“c” are not.
    Vasya painted the resulting graph near the string and then erased the string. Next day Vasya’s friend Petya came to a lecture and found some graph at his desk. He had heard of Vasya’s adventure and now he wants to find out whether it could be the original graph G , painted by Vasya. In order to verify this, Petya needs to know whether there exists a string s , such that if Vasya used this s s he would produce the given graph G .

輸入輸出格式

輸入格式:

The first line of the input contains two integers n and m 在這裡插入圖片描述 — the number of vertices and edges in the graph found by Petya, respectively.

Each of the next m lines contains two integers u i u_{i} and v i v_{i} ( 1 < = u i , v i < = n , u i v i ) (1<=u_{i},v_{i}<=n,u_{i}≠v_{i}) — the edges of the graph G . It is guaranteed, that there are no multiple edges, that is any pair of vertexes appear in this list no more than once.

輸出格式:

In the first line print “Yes” (without the quotes), if the string s Petya is interested in really exists and “No” (without the quotes) otherwise.

If the string s exists, then print it on the second line of the output. The length of s must be exactly n , it must consist of only letters “a”, “b” and “c” only, and the graph built using this string must coincide with G . If there are multiple possible answers, you may print any of them.

輸入輸出樣例
輸入樣例#1:

2 1
1 2

輸出樣例#1: 複製

Yes
aa

輸入樣例#2:

4 3
1 2
1 3
1 4

輸出樣例#2:

No

說明

In the first sample you are given a graph made of two vertices with an edge between them. So, these vertices can correspond to both the same and adjacent letters. Any of the following strings “aa”, “ab”, “ba”, “bb”, “bc”, “cb”, “cc” meets the graph’s conditions.

In the second sample the first vertex is connected to all three other vertices, but these three vertices are not connected with each other. That means that they must correspond to distinct letters that are not adjacent, but that is impossible as there are only two such letters: a and c.


先描述一下題意吧:

給出一個由字串 s s 建圖的過程,

  • 字元僅有 a , b , c a,b,c 三種,建出的圖中第 i i 個頂點表示原來的第 i i 個字元。
  • i i j j 有連邊,當且僅當 s [ i ] s[i] s [ j ] s[j] 相同或 s [ i ] s[i] s [ j ] s[j] 是相鄰的字元( a a b b 相鄰, b b c c 相鄰)

現給出由某個字串 s s 建出的圖,構造一個字串使其符合上面的要求要求,或者回答不存在這樣的字串。

輸入:

第一行兩個整數 n , m n,m ,表示節點數(即字串長度)和邊數
接下來 m m 行,每行兩個數字 u i u_{i} and v i v_{i} ,表示這兩個節點之間有一條邊

輸出:

如果字串存在,第一行輸出一個$“Yes”,第二行輸出符合條件的字串。

如果不存在,僅在第一行輸出一個“No”;


講解時間:

由題意可知, b b 與所有的點都有連邊,我們很容易就可以找出 b b

反過來想,只有 a , c a,c 之間有沒有連的邊,那麼我們把圖反過來,準確的說是建原圖的補圖,

如果有符合條件的字串,那這個補圖一定是個二分圖,那麼對補圖進行二分圖染色就完成了。

注意一下,在補圖中一條邊都沒有的即為點 b b ,我們並不需要對它進行處理,只在最後輸出就可以啦。

程式碼:
#include<iostream>
#include<cstdio>
#include<ctype.h>
#include<cstring>
#include<cstdlib>
#define _ 0
using namespace std;
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch))f|=ch=='-',ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return f?-x:x;
}
int head[507],cnt;
struct Edge{
    int next,to;
}edge[500007];
bool ma[507][507];//用鄰接矩陣存圖,方便建補圖
int col[507];
inline void Byebye(){printf("No\n");exit( ~~(0^_^0) );}//有點閒..
inline void add_edge(int from,int to){
    edge[++cnt].next=head[from];
    edge[cnt].to=to;head[from]=cnt;
}
bool dfs(int x){//二分圖染色
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(col[to]==col[x])return 0;
        if(~col[to])continue;col[to]=col[x]^1;
        if(!dfs(to))return 0;
    }
    return 1;
}
int main(){
    int n=read(),m=read();
    for(int i=1;i<=m;++i){
        int u=read(),v=read();
        ma[u][v]=ma[v][u]=1;
    }
    for(int i=1;i<=n;++i)for(int j=1;j<i;++j)//建補圖
        if(!ma[i][j])add_edge(i,j),add_edge(j,i);
    memset(col,-1,sizeof col);//染色陣列置為-1,最後若依舊為-1,即為b
    for(int i=1;i<=n;++i){
        if(~col[i] || !head[i])continue;
        col[i]=0;
        if(!dfs(i))Byebye();//染色基本套路,若不符合條件輸出No,退出程式
    }
    for(int i=1;i<=n;++i)for(int j=1;j<i;++j)
        if(ma[i][j] && col[i]+col[j]==1)Byebye();//檢查a,c之間是否有連邊
    printf("Yes\n");
    for(int i=1;i<=n;++i)putchar(~col[i]?!col[i]?'a':'c':'b');//輸出一種即可
    return 0;//好習慣
}