codeforces 653E. Bear and Forgotten Tree 2 连通问题

E. Bear and Forgotten Tree 2
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

A tree is a connected undirected graph consisting of n vertices and n  -  1 edges. Vertices are numbered 1 through n.

Limak is a little polar bear. He once had a tree with n vertices but he lost it. He still remembers something about the lost tree though.

You are given m pairs of vertices (a1, b1), (a2, b2), ..., (am, bm). Limak remembers that for each i there was no edge between ai andbi. He also remembers that vertex 1 was incident to exactly k edges (its degree was equal to k).

Is it possible that Limak remembers everything correctly? Check whether there exists a tree satisfying the given conditions.

Input

The first line of the input contains three integers nm and k () — the number of vertices in Limak's tree, the number of forbidden pairs of vertices, and the degree of vertex 1, respectively.

The i-th of next m lines contains two distinct integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi) — the i-th pair that is forbidden. It's guaranteed that each pair of vertices will appear at most once in the input.

Output

Print "possible" (without quotes) if there exists at least one tree satisfying the given conditions. Otherwise, print "impossible" (without quotes).

Examples
input
5 4 2
1 2
2 3
4 2
4 1
output
possible
input
6 5 3
1 2
1 3
1 4
1 5
1 6
output
impossible
Note

In the first sample, there are n = 5 vertices. The degree of vertex 1 should be k = 2. All conditions are satisfied for a tree with edges1 - 55 - 21 - 3 and 3 - 4.

In the second sample, Limak remembers that none of the following edges existed: 1 - 21 - 31 - 41 - 5 and 1 - 6. Hence, vertex 1couldn't be connected to any other vertex and it implies that there is no suitable tree.


题意:n个点,m条不能相连的边,点1的度为k(相连的边有且仅有k条)。问是否能构成一棵树。


理解:一开始想连接所有边,删除这m条边,dfs一下,然后看了数据范围就崩了。

然后就想,1的度为这么多,那么用1去连接其他联通块,1分别与其他联通块(联通块里面瞎连都能成一棵树)连接,如果连出来的边数小于等于k就是可行的(多的边可以瞎连啊),连出来的边数大于k就不行了,不符合题设。

还有个问题是点1与每个联通块是否能相连的问题,这个可以在跑联通块的过程中处理,看到别人的,感觉挺巧妙的。

还有就是缩点,就是把一个连通块压缩成一个点,感觉好腻害的样子,新姿势

CODE

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 3e5+10;

int n,m,k;
set tar;     ///剩余联通块
set v[maxn]; ///每个点不能连的点
bool vis[maxn];   ///标记


int bfs(int st)
{
    int flag = 0;
    vis[st] = true;
    queue q;
    q.push(st);
    vectore;
    while(!q.empty())
    {
        st = q.front();
        q.pop();
        for(set::iterator it = tar.begin(); it != tar.end(); it++)  ///第一次用set迭代
        {
            if(*it != st && !vis[*it] && !v[st].count(*it))
            {
                q.push(*it);
                e.push_back(*it);
                vis[*it] = true;
            }
        }
        if(!v[st].count(1)) flag = 1;      ///判断是否连通块里面是否能有一个点与点1相连
        for(int i = 0;i < e.size();i++)    ///当前点连接的点全部删掉
            tar.erase(e[i]);
        e.clear();
    }
    return flag;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int num1 = n-1;
    for(int i = 1;i <= m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        v[a].insert(b);
        v[b].insert(a);
        if(a == 1 || b == 1) num1--;
    }
    if(num1 < k)                ///如果能和1相连的边少于k,impossible
    {
        printf("impossible\n");
        return 0;
    }
    for(int i = 2;i <= n;i++)   ///把除1以外所有点压入set进行缩点
        tar.insert(i);
    memset(vis,false,sizeof(vis));
    for(int i = 2;i <= n;i++)
    {
        if(!vis[i])
        {
            if(bfs(i) == 0)
            {
                printf("impossible\n");
                return 0;
            }
        }
    }
    if(tar.size() > k)            ///如果联通块的数量多余k则impossible
        puts("impossible");
    else
        puts("possible");
    return 0;
}



你可能感兴趣的:(图论)