兰道定理(竞赛图)
所謂蘭道定理,就是蘭道定下的道理
(逃)
解析
每條邊被規定了方向的完全圖叫做競賽圖
競賽圖中,設每個點的出度為uiu_iui?
顯然有:
∑ui=n×(n?1)2\sum u_i=\dfrac{n\times(n-1)}{2}∑ui?=2n×(n?1)?
而蘭道定理的內容是:
若n個點的出度序列升序排序后為sis_isi?,那么其能構成競賽圖的充要條件是,對于任意的k屬于[1,n],都有:
∑i=1ksi>=k×(k?1)2\sum_{i=1}^ks_i>=\dfrac{k\times(k-1)}{2}i=1∑k?si?>=2k×(k?1)?
當且僅當k=n時,取等
必要性比較顯然,現在的關鍵是充分性
蘭道定理的證明類似于裴蜀定理,是一種構造的方法
先構造出一個競賽圖 TTT ,滿足任意一點 i 都只對比自己編號小的點連邊,設其出度為uiu_iui?
顯然,ui=i?1u_i=i-1ui?=i?1
然后考慮如下操作:
找到第一個位置,使得si>uis_i>u_isi?>ui?,設為 xxx
找到最靠后的 yyy ,滿足 sx=sys_x=s_ysx?=sy?(xy可以相等)
找到第一個位置,使得 si<uis_i<u_isi?<ui? 設為 zzz
此時由于uz>sz>=sy>uyu_z > s_z>=s_y>u_yuz?>sz?>=sy?>uy?,可以得出,uz?uy>=2u_z-u_y>=2uz??uy?>=2,因此,一定存在第三個點p,使得z連向p且p連向y
調換(z,p)(z,p)(z,p)和(y,p)(y,p)(y,p)的方向,此時只有uzu_zuz?減小1,uyu_yuy?增大1,而upu_pup?不變
不斷重復以上流程,直到uuu和sss完全相同
代碼
CF850D:Tournament Construction
#include<bits/stdc++.h> using namespace std; const int N=3e5+100; const int mod=1e9+7; double eps=1e-10; #define ll long long ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f; }int n,m;int dp[35][100][2050],num[35][100][2050]; int a[35],pre[35]; int u[2005],s[2005],tot; void find(int k,int x,int w){if(k==0) return;find(k-1,x-num[k][x][w],w-num[k][x][w]*a[k]);for(int i=1;i<=num[k][x][w];i++) s[++tot]=a[k];return; } bool jd[2050][2050]; inline void rev(int x,int y){if(jd[x][y]){u[x]--;u[y]++;}else{u[y]--;u[x]++;}jd[x][y]^=1;jd[y][x]^=1; } int main(){#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);#endifn=read();for(int i=1;i<=n;i++) a[i]=read();sort(a+1,a+1+n);dp[0][0][0]=1;int k(0);for(k=1;;k++){for(int i=1;i<=n;i++){if(i>k) break;for(int w=k*(k-1)/2;w<=2000;w++){for(int j=1;j<=k&&j*a[i]<=w;j++){if(dp[i-1][k-j][w-j*a[i]]){num[i][k][w]=j;dp[i][k][w]=1;}}}}if(dp[n][k][k*(k-1)/2]) break;}//printf("ok k=%d\n",k);find(n,k,k*(k-1)/2);//for(int i=1;i<=k/2;i++) swap(s[i],s[k-i+1]);for(int i=1;i<=k;i++) u[i]=i-1;for(int i=1;i<=k;i++){for(int j=1;j<i;j++) jd[i][j]=1;}while(1){int x(0),y(0),z(0),p(0);//for(int i=1;i<=k;i++) printf("%d ",s[i]);putchar('\n');//for(int i=1;i<=k;i++) printf("%d ",u[i]);putchar('\n');for(int i=1;i<=k;i++){if(s[i]>u[i]){x=i;break;}}if(!x) break;y=x;for(int i=x+1;i<=k;i++) if(u[i]==u[x]) y=x;for(int i=k;i>=1;i--) if(u[i]>s[i]) z=i;//printf("x=%d y=%d z=%d\n",x,y,z);for(p=1;p<=k;p++){if(jd[z][p]&&!jd[y][p]){//printf("x=%d y=%d z=%d p=%d\n",x,y,z,p);rev(z,p);rev(y,p);break;}}}printf("%d\n",k);for(int i=1;i<=k;i++){for(int j=1;j<=k;j++){printf("%d",jd[i][j]);}putchar('\n');}return 0; } /* 2 3 7 4 9 9 1 2 8 3 1 4 2 4 */總結
- 上一篇: CF1406E:Deleting Num
- 下一篇: 电脑插耳机没有声音怎么回事 电脑插耳机没