System Administrator(构造,图论)
Bob got a job as a system administrator in X corporation. His first task was to connect n servers with the help of mtwo-way direct connection so that it becomes possible to transmit data from one server to any other server via these connections. Each direct connection has to link two different servers, each pair of servers should have at most one direct connection. Y corporation, a business rival of X corporation, made Bob an offer that he couldn't refuse: Bob was asked to connect the servers in such a way, that when server with index v fails, the transmission of data between some other two servers becomes impossible, i.e. the system stops being connected. Help Bob connect the servers.
The first input line contains 3 space-separated integer numbers n, m, v (3 ≤ n ≤ 105, 0 ≤ m ≤ 105, 1 ≤ v ≤ n), n — amount of servers, m — amount of direct connections, v — index of the server that fails and leads to the failure of the whole system.
If it is impossible to connect the servers in the required way, output -1. Otherwise output m lines with 2 numbers each — description of all the direct connections in the system. Each direct connection is described by two numbers — indexes of two servers, linked by this direct connection. The servers are numbered from 1. If the answer is not unique, output any.
5 6 3
1 2
2 3
3 4
4 5
1 3
3 5
6 100 1
-1
思路:由题意,图为连通图,要使得去除v后,图中至少有两个点不能通信(即此时至少有两个连通分支),则v为割点。
要构造出v为割点的图很容易,将图的顶点集合V分为V1和V2两部分,其中V1包含v,而V2不包含v,且V2中的顶点不和{V1-v}中的任何顶点相邻,而V1和{V2+v}中的顶点又各自两两互通。例子如下(红色圈是v):
程序如何实现?将n个顶点划分为V1和V2两部分,从V1(|V1|>=2)中任选一个点作为v,然后从v出发向其他所有顶点各引一条边,如果不满m条边,就在V1和V2内部连边(V1和V2之间不能连边)直至图中已有m条边。
如何确定什么时候无解?这需要求出在顶点数为n的情况下边数m的最大值和最小值。由于图连通,易知m>=n-1。重点是求m的最大值。假设V1和V2各有k和(n-k)个点,V1内部最多k*(k-1) / 2条边,V2内部最多有 (n-k)*(n-k-1) / 2条边,而V2和v之间最多有n-k条边,则m<=k*(k-1) / 2+ (n-k)*(n-k-1) / 2 + n-k ,由一元二次方程知识知当k与(n+1)/2差的绝对值越大,m的最大值越大,于是k为1或n-1。所以m最大时,V1有n-1个点而V2有一个点。故m<=(n-1)*(n-2)/2+1.于是得n-1 <= m <= (n-1)*(n-2)/2+1.
最终思路:取相异两点v和u,v的意义如前,u是V2的唯一一个顶点,将v与所有其他顶点连边(自然包括与u连边),如果此时边数不足m,在V1内部连边直至边数为m
1 #include <iostream> 2 #include <algorithm> 3 #include <string> 4 #include <queue> 5 #include <vector> 6 #include <cmath> 7 #include <cstdio> 8 #include <cstring> 9 using namespace std; 10 11 const int SZ = 100002; 12 int n, m, v; 13 bool vis[SZ]; 14 15 int main() 16 { 17 while(scanf("%d %d %d", &n, &m, &v) != EOF) 18 { 19 if(m < n - 1 || m > ((n - 2) * (n - 3)) / 2 + n - 1) 20 puts("-1"); 21 else if(n < 3) 22 { 23 puts("1 2"); 24 } 25 else 26 { 27 int u = v - 1; 28 if(v == 1) u = 2; 29 for(int i = 1; i <= n; i++) 30 { 31 if(i != v) 32 printf("%d %d\n", i, v); 33 } 34 m -= (n - 1); 35 for(int i = 1; i <= n && m; i++) 36 { 37 if(i == v || i == u) continue; 38 for(int j = i + 1; j <= n && m; j++) 39 { 40 if(j == v || j == u) continue; 41 printf("%d %d\n", i , j); 42 m--; 43 } 44 } 45 } 46 } 47 return 0; 48 }