CF 976D Degree Set

xiaoxiao2021-02-28  57

传送门题目大意思路参考代码总结

传送门
题目大意

  给你一个长度为 n n 的正整数序列 d1,d2,,dnd1,d2,⋯,dn d1<d2<<dn d 1 < d 2 < ⋯ < d n )。要求你构造一个满足以下条件的无向图:

有恰好 dn+1 d n + 1 个点;没有自环;没有重边;总边数不超过 106 10 6 ;它的度数集合等于 d d

  点从 11 标号至 dn+1 d n + 1

  图的度数序列是一个长度与图的点数相同的数组 a a ,其中 aiai 是第 i i 个顶点的度数(与其相邻的顶点数)。

  图的度数集合是度数序列排序后去重的结果。

  保证有解,要求输出符合条件的图。

思路

  唉,我太弱了,这么傻逼的构造题,硬是做了两节课都没做出来,还是看了题解才做出来的,唉,太弱啦!

  显然至少有一个点是连接了其它所有点的,那至多有多少个点连接了其它所有点呢?显然是 d1d1 个点。这样,就不存在度数为 d1 d 1 dn d n 的点了,并且 d2n1 d 2 ∼ n − 1 的所有值都要减去 d1 d 1 。我们强制让还有度数的点的数量为 dn1+1 d n − 1 + 1 ,构造方法为:令度数为 d1 d 1 的点的个数为 dndn1 d n − d n − 1 (显然至少为 1 1 ),将度数为 dndn 的点连向其它所有点,那么点数将会减少 d1+(dndn1) d 1 + ( d n − d n − 1 ) 。这时,以前度数为 dn1 d n − 1 的点度数变成了 dn1d1 d n − 1 − d 1 ,因为有 dn1d1+1=dn+1(d1+(dndn1)) d n − 1 − d 1 + 1 = d n + 1 − ( d 1 + ( d n − d n − 1 ) ) ,所以原问题变成了一个子问题,递归求解即可。

参考代码
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <cassert> #include <cctype> #include <climits> #include <ctime> #include <iostream> #include <algorithm> #include <vector> #include <string> #include <stack> #include <queue> #include <deque> #include <map> #include <set> #include <bitset> #include <list> #include <functional> typedef long long LL; typedef unsigned long long ULL; using std::cin; using std::cout; using std::endl; typedef int INT_PUT; INT_PUT readIn() { INT_PUT a = 0; bool positive = true; char ch = getchar(); while (!(ch == '-' || std::isdigit(ch))) ch = getchar(); if (ch == '-') { positive = false; ch = getchar(); } while (std::isdigit(ch)) { a = a * 10 - (ch - '0'); ch = getchar(); } return positive ? -a : a; } void printOut(INT_PUT x) { char buffer[20]; int length = 0; if (x < 0) putchar('-'); else x = -x; do buffer[length++] = -(x % 10) + '0'; while (x /= 10); do putchar(buffer[--length]); while (length); } const int maxn = 1005; const int maxm = 305; int n, m; int a[maxn]; std::vector<std::pair<int, int> > G; void run() { m = readIn(); for (int i = 1; i <= m; i++) a[i] = readIn(); n = a[m] + 1; int l = 1; int start = 1; int accum = 0; int r = m; for (int i = 1; i <= r; i++) { for (int j = 1; j <= a[i]; j++) { for (int k = start + 1; k <= accum + a[r] + 1; k++) { G.push_back(std::make_pair(start, k)); } start++; } r--; accum += a[i]; for (int j = i + 1; j <= m; j++) a[j] -= a[i]; } printOut(G.size()); for (int i = 0; i < G.size(); i++) { putchar('\n'); printOut(G[i].first); putchar(' '); printOut(G[i].second); } } int main() { run(); return 0; }
总结

  最关键的是如何想到度数为 d1 d 1 的点数为多少。这里为了构造,很显然我们要往子问题那里去靠。如果满足子问题结构,设度数为 d1 d 1 的点数为 k k ,那么有:

dn1d1 1=dnd1 1kdn−1−d1 1=dn−d1 1−k

  显然有 k=dndn1 k = d n − d n − 1 ,相当于是我们先用度数为 dn+1 d n + 1 的把所有度数为 d1 d 1 的消掉,并且把自己的度数变成 dn1 d n − 1

  需要注意的是,我们是令点数为 dn1+1 d n − 1 + 1 ,但是度数都减去了 d1 d 1 ,递归求解时 dn1 d n − 1 发生了改变。

转载请注明原文地址: https://www.6miu.com/read-2620231.html

最新回复(0)