codeforces 1082D Maximum Diameter Graph

本文探讨了如何根据给定点的度数序列构建一个连通图,使得该图的直径尽可能大,同时确保图中没有自环和多重边。文章提供了一种算法思路,包括检查是否可以形成连通图的条件,以及如何通过将度数大于1的点连成链,并将剩余点连接到链的两端来构造最优解。

Graph constructive problems are back! This time the graph you are asked to build should match the following properties.

The graph is connected if and only if there exists a path between every pair of vertices.

The diameter (aka "longest shortest path") of a connected undirected graph is the maximum number of edges in the shortest path between any pair of its vertices.

The degree of a vertex is the number of edges incident to it.

Given a sequence of nn integers a1,a2,,ana1,a2,…,an construct a connected undirected graph of nn vertices such that:

  • the graph contains no self-loops and no multiple edges;
  • the degree didi of the ii-th vertex doesn't exceed aiai (i.e. diaidi≤ai);
  • the diameter of the graph is maximum possible.

Output the resulting graph or report that no solution exists.

Input

The first line contains a single integer nn (3n5003≤n≤500) — the number of vertices in the graph.

The second line contains nn integers a1,a2,,ana1,a2,…,an (1ain11≤ai≤n−1) — the upper limits to vertex degrees.

Output

Print "NO" if no graph can be constructed under the given conditions.

Otherwise print "YES" and the diameter of the resulting graph in the first line.

The second line should contain a single integer mm — the number of edges in the resulting graph.

The ii-th of the next mm lines should contain two integers vi,uivi,ui (1vi,uin1≤vi,ui≤n, viuivi≠ui) — the description of the ii-th edge. The graph should contain no multiple edges — for each pair (x,y)(x,y) you output, you should output no more pairs (x,y)(x,y) or (y,x)(y,x).

题意:输入n个点的度,输出能否成为连通图和图的最大直径,和构成连通图的连接边。

思路:首先我们先看这个能不能连成图,每个点之间相连的话,度数和要大于等于2*n-2。图连接的方法现将度数大于1的连成一条链,再将剩下的连在图的两边,就可以想得到最优解。

 1 #include <vector>
 2 #include <string>
 3 #include <iostream>
 4 #include <string.h>
 5 #include <sstream>
 6 #include <cstdio>
 7 #include <map>
 8 using namespace std;
 9 const int inf = 0x3f3f3f3f;
10 const int Maxn = 10010;
11 int a[Maxn];
12 typedef long long ll;
13 int tot=0;
14 
15 int main()
16 {
17     int n;
18     scanf("%d",&n);
19     int sum = 0;
20     for(int i=0;i<n;i++)
21     scanf("%d",&a[i]),sum+=a[i];
22     if(sum<2*n-2) {cout<<"NO\n"<<endl; return 0;}//判断能否形成连通图
23     vector<int> one;
24     for(int i=0;i<n;i++)//将度为1的挑选出来
25     {
26         if(a[i]==1)
27         a[i]=0,one.push_back(i);
28     }
29     int t=one.size();
30     cout<<"YES "<<n-t-1+min(2,t)<<endl<<n-1<<endl;//连通图的边数等于点减一
31     int lst=-1;
32     if(!one.empty())
33     {
34         lst = one.back();
35         one.pop_back();
36     }
37     for(int i=0;i<n;i++)//将度数大于1的连成链
38     {
39         if(a[i]>1)
40         {
41             if(lst != -1)
42             {
43                 --a[lst];
44                 --a[i];
45                 printf("%d %d\n",lst+1,i+1);
46             }
47             lst = i;
48         }
49     }
50     for(int i=n-1;i>=0;i--)//将度数等于1的尽量连在右侧
51     {
52         while(a[i]>0&&!one.empty())
53         {
54             --a[i];
55             printf("%d %d\n",i+1,one.back()+1);
56             one.pop_back();
57         }
58     }
59     return 0;
60 }

 

 

转载于:https://www.cnblogs.com/wangxwws/p/10063005.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值