SRM 717 DIV 1 中 出了这样一道题:

竞赛图就是把一个无向完全图的边定向后得到的有向图,得分序列就是每个点的出度构成的序列。

给出一个合法的竞赛图出度序列, 要求构造出原图(原题是求(u, v)有路径的点对数,似乎有不需要构造出原图的方法)。

当时我的做法是 直接构造一个网络,跑最大流。

比赛后总觉得这个题有什么神奇的性质,于是搜了一下相关资料:

有一篇关于得分序列的论文:
http://www.sciencedirect.com/science/article/pii/0095895679900455?via%3Dihub

其中介绍了一个性质:

Landau Theorem: 竞赛图的出度序列为${s_i}$的充要条件是 对于任意的子集X,$\sum\limits_{i \in X} s_i \ge \tbinom{|X|}{2}$

1.必要性很容易证明:如果${s_i}$是竞赛图的得分序列, 对于任意一个子集X, 它的得分之和一定大于等于它内部点之间的得分和。

2.充分性证明: 大致思路是构造一个二分图然后利用Hall定理 证明完美匹配。

 首先把边<i, j> (i < j) 看做左边的点。 右边部分,对于每个$s_i$ 搞出$s_i$个点(这些点记为$i$类点)。

 对于左边的点<i, j> ,  向右边所有的$i$类点和$j$类点各连一条边。 显然一个完美匹配 和 一个原图对应。

根据Hall定理,有完美匹配的充要条件是  对于左边任意的点集X,   $|H(X)| \ge |X|$.  $H(X)$是右边与$X$中的点有边相连的点的集合。

对于左边任意的点集$X$, 设集合$Y$为$X$中的边的端点的集合。 即$Y = \{ x | (x, t) \in X  \ or\  (t, x) \in X \}$

根据所给的条件, 我们有 $ |X| \leq \tbinom{|Y|}{2} \leq \sum\limits_{i \in Y} s_i = |H(X)|$, 所以存在完美匹配。定理得证。

接下来我们怎么用这个定理来构造原图呢?

当然可以构造出二分图然后跑最大匹配。

我自己又YY了一种贪心做法:

大致思想是不断给边定向,但是要让得分序列满足Landau Theorem。

先将所有点按$s_i$ 从小到大排序, 考虑 $s_i$最小的那个点x, 有$n - 1 - s_i$ 条边指向它, 我们确定哪些点向它连边,让这些点的score -1. 显然贪心一下 让score 最大的$n - 1 - s_i$个点 向它连边最优。    对于其它的点, x向它们连边就好。

AC代码:

 // BEGIN CUT HERE  

 // END CUT HERE
#line 5 "ScoresSequence.cpp"
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
using namespace std;
#define N 102
const int INF = 1e9 + ; bool a[N][N];
vector<pair<int, int> > lis, tmp; class ScoresSequence
{
public:
int count(vector <int> s)
{
int n = s.size();
memset(a, , sizeof(a));
for (int i = ; i < n; ++i) a[i][i] = true; lis.clear();
for (int i = ; i < n; ++i) lis.push_back(make_pair(s[i], i)); for (int i = ; i < n - ; ++i)
{
sort(lis.begin(), lis.end());
int c = n - i - lis[].first - ;
for (int k = ; k <= c; ++k)
{
lis[n - i - k].first--;
a[lis[n - i - k].second][lis[].second] = true;
}
for (int k = ; k < n - i - c; ++k)
a[lis[].second][lis[k].second] = true;
tmp.clear();
for (int j = ; j < lis.size(); ++j) tmp.push_back(lis[j]);
lis = tmp;
}
int ans = ;
for (int k = ; k < n; ++k)
for (int i = ; i < n; ++i)
for (int j = ; j < n; ++j)
a[i][j] |= a[i][k] & a[k][j];
for (int i = ; i < n; ++i)
for (int j = ; j < n; ++j)
ans += a[i][j];
return ans;
} // BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -) || (Case == )) test_case_0(); if ((Case == -) || (Case == )) test_case_1(); if ((Case == -) || (Case == )) test_case_2(); if ((Case == -) || (Case == )) test_case_3(); if ((Case == -) || (Case == )) test_case_4(); }
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { int Arr0[] = {, , }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); int Arg1 = ; verify_case(, Arg1, count(Arg0)); }
void test_case_1() { int Arr0[] = {, , }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); int Arg1 = ; verify_case(, Arg1, count(Arg0)); }
void test_case_2() { int Arr0[] = {, , }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); int Arg1 = ; verify_case(, Arg1, count(Arg0)); }
void test_case_3() { int Arr0[] = {, , , , , , , , , }; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); int Arg1 = ; verify_case(, Arg1, count(Arg0)); }
void test_case_4() { int Arr0[] = {,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[]))); int Arg1 = ; verify_case(, Arg1, count(Arg0)); } // END CUT HERE }; // BEGIN CUT HERE
int main()
{
ScoresSequence ___test;
___test.run_test(-);
system("pause");
}
// END CUT HERE

实现方法比较暴力,大概是 O(n^2 logn)

竞赛图的得分序列 (SRM 717 div 1 250)的更多相关文章

  1. TopCoder SRM 596 DIV 1 250

    body { font-family: Monospaced; font-size: 12pt } pre { font-family: Monospaced; font-size: 12pt } P ...

  2. SRM 719 Div 1 250 500

    250: 题目大意: 在一个N行无限大的网格图里,每经过一个格子都要付出一定的代价.同一行的每个格子代价相同. 给出起点和终点,求从起点到终点的付出的最少代价. 思路: 最优方案肯定是从起点沿竖直方向 ...

  3. Topcoder SRM 661 (Div.1) 250 MissingLCM - 数论

    [题意] 给你一个数N(1<=N<=10^6),要求最小的M(M>N),使得lcm(n+1,n+2,...m)=lcm(1,2,3,...,m) [思路] 手速太慢啦,等敲完代码的时 ...

  4. Topcoder SRM 656 (Div.1) 250 RandomPancakeStack - 概率+记忆化搜索

    最近连续三次TC爆零了,,,我的心好痛. 不知怎么想的,这题把题意理解成,第一次选择j,第二次选择i后,只能从1~i-1.i+1~j找,其实还可以从j+1~n中找,只要没有被选中过就行... [题意] ...

  5. 【topcoder SRM 702 DIV 2 250】TestTaking

    Problem Statement Recently, Alice had to take a test. The test consisted of a sequence of true/false ...

  6. Topcoder口胡记 SRM 562 Div 1 ~ SRM 599 Div 1

    据说做TC题有助于提高知识水平? :) 传送门:https://284914869.github.io/AEoj/index.html 转载请注明链接:http://www.cnblogs.com/B ...

  7. TopCoder SRM 560 Div 1 - Problem 1000 BoundedOptimization & Codeforces 839 E

    传送门:https://284914869.github.io/AEoj/560.html 题目简述: 定义"项"为两个不同变量相乘. 求一个由多个不同"项"相 ...

  8. TopCoder SRM 667 Div.2题解

    概览: T1 枚举 T2 状压DP T3 DP TopCoder SRM 667 Div.2 T1 解题思路 由于数据范围很小,所以直接枚举所有点,判断是否可行.时间复杂度O(δX × δY),空间复 ...

  9. Topcoder SRM 648 (div.2)

    第一次做TC全部通过,截图纪念一下. 终于蓝了一次,也是TC上第一次变成蓝名,下次就要做Div.1了,希望div1不要挂零..._(:зゝ∠)_ A. KitayutaMart2 万年不变的水题. # ...

随机推荐

  1. tomcat中server.xml配置详解(转载)(二)

    转载自:https://www.cnblogs.com/starhu/p/5599773.html 一:<Connector>元素 由Connector接口定义.<Connector ...

  2. 无比强大!Python抓取cssmoban站点的模版并下载

    Python实现抓取http://www.cssmoban.com/cssthemes站点的模版并下载 实现代码 # -*- coding: utf-8 -*- import urlparse imp ...

  3. chromedriver中的浏览器选项

    There are lots of command lines which can be used with the Google Chrome browser. Some change behavi ...

  4. ASP.NET MVC3 系列教程 - 模型

    I:基础绑定的实现 1.在前面的两篇基础文章(路由 及 控制器&视图)当中,还没对QueryString的绑定进行介绍,因为我觉得它更适合放在这一章节中去介绍.我们在用WebForm去开发的时 ...

  5. jquery easyUi columns日期格式化

    jquery easyUi  columns日期格式化 方法一 Date.prototype.format = function (format) { var o = { "M+" ...

  6. nodejs express route 的用法

    express 中文社区:http://expressjs.jser.us/community.html nodejs express route 的用法 1. 首先是最基本的用法. 1 2 3 4 ...

  7. GTD实用指南(转载)

    时间管理第一层:记录每日时间开支,认识自己的时间黑洞.你会惊讶地发现,每天的无意义时间很可能在70%以上. [避开时间黑洞的小策略:1.彻底关闭聊天工具:2.关掉邮件的到达提醒功能:3.保持办公环境的 ...

  8. unity,set ugui rectTransform anchor by script

    如果想用代码实现与下面面板相同的功能 试验可知改变上面选项下面四个值也随之变化: 所以说明二者是一回事儿. 因此,只要通过代码修改RectTransform的anchorMax和anchorMin成员 ...

  9. MongoDB GridFS最佳应用概述

    <MongoDB GridFS最佳应用概述> 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs GridFS是MongoDB数据库之上的一个简单 ...

  10. Vivado的helloword程序:硬件工程部分

    硬件平台:ZedBoard软件平台:vivado2013.3 本示例通过综合.实现,生成比特流,发送到SDK实现.启动vivado并且创建一个项目根据提示操作一步步创建新项目的时候记得选择RTL Pr ...