2022.7.2 CF850D&HDU5873
兰道定理
-
用途:通过度数判断和构造竞赛图。
-
内容:\(n\) 个点的出度升序排为 \(d_i\),能够成竞赛图的冲要条件是 \(\forall k,\sum\limits_{i=1}^k d_i\geqslant \frac 12 k(k-1)\)
-
证明:必要性是显然的,因为每一个大小为 \(k\) 的子图也是竞赛图。现在考虑充分性,即构造方案。这个构造比较有趣。考虑一个竞赛图所有边有大向小,设每个点度数为 \(d'_i\),一开始显然有 \(d'_i=i-1\)。此时上述不等式可以变形为 \(\forall k,\sum\limits_{i=1}^k d_i\geqslant \sum\limits_{i=1}^k d'_i\),称为性质 \(A\)。当 \(\{d\}\neq\{d'\}\) 时,我们不断重复一下操作:找到第一个 \(a\) 使得 \(d_a>d'_a\),找到最后一个 \(b\) 使得 \(d'_b=d'_a\),找到第一个 \(c\) 使得 \(d_c<d'_c\),由于性质 \(A\) 此时我们发现一定有 \(c>b\)。所以有 \(d'_c>d_c\geqslant d_b>d'_b\),即 \(d'_c-d'_b\geqslant 2\),即必然存在一个点 \(c\) 对其有连边且 \(b\) 没有,将这两条边反向,而显然操作后扔满足序列递增和性质 \(A\),证毕。
例题:CF850D Tournament Construction
不会最简单的东西了/dk,直接 \(dp\) 出答案,然后跑兰道定理的构造即可。
具体地设 \(dp_{i,j,k}\) 表示考虑到了第 \(i\) 个数,当前总共有 \(j\) 个数,和为 \(k\) 的可行性,记一下路径即可。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=32;
int n,m,a[N],b[62],G[62][62],d[62];
bool dp[N][62][2000],P[N][62][2000];
inline int chk(){
int flg=1;
for(int i=1;i<=n;i++)flg&=(b[i]==d[i]);
return flg;
}
int main(){
m=read();
for(int i=1;i<=m;i++)a[i]=read();
sort(a+1,a+1+m);
dp[0][0][0]=1;
for(int i=1;i<=m;i++)
for(int j=i;j<=61;j++)
for(int s=j*(j-1)/2;s<=1830;s++){
if(s>=a[i]&&dp[i-1][j-1][s-a[i]])dp[i][j][s]=P[i][j][s]=1;
else if(s>=a[i]&&dp[i][j-1][s-a[i]])dp[i][j][s]=1;
}
for(int i=m;i<=61;i++)
if(dp[m][i][i*(i-1)/2]){n=i;break;}
if(!n)return puts("=")&0;
printf("%d\n",n);
int now=m,S=n*(n-1)/2;
for(int i=n;i>=1;i--)
b[i]=a[now],now-=P[now][i][S],S-=b[i];
for(int i=1;i<=n;i++)d[i]=i-1;
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)G[i][j]=1;
while(!chk()){
int p1=0,p2=0,p3=0;
for(int i=1;i<=n;i++)
if(b[i]>d[i]){
p1=i;while(p1<n&&d[p1+1]==d[i])++p1;
break;
}
for(int i=1;i<=n;i++)
if(b[i]<d[i]){p2=i;break;}
for(int i=1;i<=n;i++)
if(i!=p1&&i!=p2&&G[p2][i]&&G[i][p1]){p3=i;break;}
G[p1][p3]=G[p3][p2]=1;
G[p3][p1]=G[p2][p3]=0;
d[p1]++,d[p2]--;
}
for(int i=1;i<=n;i++,puts(""))
for(int j=1;j<=n;j++)
printf("%d",G[i][j]);
return 0;
}
例题: hdu5873 Football Games
你考虑兰道定理的原理其实是每个子结构都要满足,所以同样的这里也是每个子结构都要满足分数和大于等于这个子结构所能产生的分数,排序判断就好了。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,Ti,a[maxn],b[maxn];
int main(){
while(~scanf("%d",&Ti)){
while(Ti--){
scanf("%d",&n);int sum=0,flg=1;
for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
if(sum!=n*(n-1)){puts("F");continue;}
sort(a+1,a+1+n);sum=0;
for(int i=1;i<=n&&flg;i++)
sum+=a[i],flg&=(sum>=i*(i-1));
puts(flg?"T":"F");
}
}return 0;
}
启发思考:是否每一个或者大多数的子结构类似的都有子结构满足则整体满足的性质呢?