浅学竞赛图
wjyppm1403 · · 算法·理论
可能更好的阅读体验
1. 定义
竞赛图,即任意两点之前有且仅有一条边的有向图。即有向完全图,有
至于为什么叫竞赛图,就是赢得点向输的点连边,一个边代表的是胜负关系。
2. 性质
兰道定理(竞赛图判定)
我们定义比分序列为将每个点的出度
那么若满足
必要性显然,考虑充分性证明,我们构造初始图,对于
未构造完成时开头必然是一段等于后面接一个
此时有
当
注意,这里定理都是存在,对于同一个比分序列可能对应本质不同的竞赛图。
兰道定理实质
兰道定理的实质是在一个序列和一定时,可以对于任意两个有关系(边)的位置进行相等量的调整(
竞赛图强连通分量个数(推论)
即:
其中
竞赛图有个很好的性质:一定存在一条哈密尔顿路径。
考虑设
显然有
考虑
那么剩下的怎么求,考虑将图划分为两个块,一个块是供 1 走的块,剩下的块不给 1 走,但是可能不存在不给 1 走的块。
那么有
时间复杂度
CF913F
令
考虑倒推答案,设
最后一个 SCC 的大小,有:
但是
考虑
考虑
时间
UOJ961 赛场设计
如何判断一个图是不是好图?你发现首先这个图一定是一个 DAG;其次考虑建出其不可达关系图,我们会发现这个图比竞赛图还密集,一些竞赛图的结论在这个图上仍然成立:
- 缩点后是一条链。
- 任意一个 SCC 大小不超过 3。
我们可以考虑 DP 求解,设
有转移:
初始化
3.2 SCC 及其拓展
CF1268D
两个结论:
- 对于
n\ge 4 ,n 阶强联通竞赛图具有n-1 阶强联通子图。 - 对于
n\ge 7 ,n 阶竞赛图存在一种翻转方案使得只需要翻转一个结点就能让它强联通。
对于
证明可以看其他题解:题解 CF1268D 【Invertation in Tournament】
#include<bits/stdc++.h>
using namespace std;
constexpr int MN=2520,MOD=998244353;
int n,cf[MN],h[MN];
bool mp[MN][MN];
bool check(){
sort(cf+1,cf+1+n);
for(int i=2;i<=n;i++) cf[i]+=cf[i-1];
for(int i=1;i<n;i++){
if(cf[i]==i*(i-1)/2) return 0;
}
return 1;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c;
cin>>c;
mp[i][j]=c-'0';
h[i]+=mp[i][j];
}
}
for(int i=1;i<=n;i++) cf[i]=h[i];
if(check()){
cout<<"0 1";
return 0;
}
int ret=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cf[j]=h[j];
for(int j=1;j<=n;j++){
cf[i]-=mp[i][j]*2-1;
cf[j]+=mp[i][j]*2-1;
}
if(check()) ret++;
}
if(ret){
cout<<1<<" "<<ret;
return 0;
}
if(n==4) cout<<-1;
if(n==6) cout<<"2 18";
return 0;
}
P3561 [POI 2017] Turysta
定理上面都讲完了,先缩点,然后对于每个强连通分量,求哈密顿回路。然后就可以对任意一个强连通分量任意点进,任意点出了。
怎么构造可以去看其他题解的构造。
#include<bits/stdc++.h>
using namespace std;
constexpr int MN=2e3+15;
int n,tcnt,nxt[MN],a[MN][MN],in[MN],tpos[MN],pos[MN];
vector<int> adj[MN],G[MN],dcc[MN],ans[MN];
namespace Tarjan{
int dfn[MN],low[MN],s[MN],col[MN],ctot,top,dtot;
bool vis[MN];
void tarjan(int u){
low[u]=dfn[u]=++dtot;
s[++top]=u;
vis[u]=1;
for(auto v:adj[u]){
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
ctot++;
int p;
do{
p=s[top--];
col[p]=ctot;
vis[p]=0;
}while(p!=u);
}
}
}using namespace Tarjan;
void toposort(){
queue<int> q;
for(int i=1;i<=ctot;i++){
if(!in[i]) q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
tpos[++tcnt]=u;
pos[u]=tcnt;
for(auto v:G[u]){
in[v]--;
if(!in[v]) q.push(v);
}
}
}
void getham(int c){
if(dcc[c].size()==1) return;
int s=dcc[c][0],t=s;
for(int i=1;i<dcc[c].size();i++){
int x=dcc[c][i];
if(a[t][x]) nxt[t]=x,t=x;
else if(a[x][s]) nxt[x]=s,s=x;
else{
for(int j=s;j!=t;j=nxt[j]){
if(a[j][x]&&a[x][nxt[j]]){
nxt[x]=nxt[j];
nxt[j]=x;
break;
}
}
}
}
t=0;
for(int i=nxt[s];i;i=nxt[i]){
if(t){
if(a[i][s]){
t=i;
continue;
}
for(int j=s,k=nxt[s];j!=t;j=k,k=nxt[k]){
if(a[i][k]){
nxt[j]=nxt[t];
nxt[t]=s;
s=k;
t=i;
break;
}
}
}else if(a[i][s]) t=i;
}
nxt[t]=s;
}
int main(){
cin>>n;
for(int i=2;i<=n;i++){
for(int j=1;j<=i-1;j++){
int x;
cin>>x;
if(x){
adj[j].push_back(i);
a[j][i]=1;
}else{
adj[i].push_back(j);
a[i][j]=1;
}
}
}
for(int i=1;i<=n;i++){
if(!dfn[i]) Tarjan::tarjan(i);
}
for(int i=1;i<=n;i++){
dcc[col[i]].push_back(i);
}
for(int u=1;u<=n;u++){
for(auto v:adj[u]){
if(col[u]!=col[v]){
G[col[u]].push_back(col[v]);
in[col[v]]++;
}
}
}
toposort();
for(int i=1;i<=tcnt;i++){
getham(tpos[i]);
}
for(int i=1;i<=n;i++){
int lst=i,now=pos[col[i]];
while('QWQ'){
if(dcc[tpos[now]].size()==1){
ans[i].push_back(lst);
if(now==tcnt) break;
lst=dcc[tpos[++now]][0];
continue;
}
ans[i].push_back(lst);
for(int j=nxt[lst];j!=lst;j=nxt[j]){
ans[i].push_back(j);
}
if(now==tcnt) break;
lst=dcc[tpos[++now]][0];
}
}
for(int i=1;i<=n;i++){
cout<<ans[i].size()<<' ';
for(auto p:ans[i]) cout<<p<<" ";
cout<<'\n';
}
return 0;
}
4. 参考
- 竞赛图的一些性质 - _zwl - 博客园
- 【CF913F】Strongly Connected Tournament - heyujun - 博客园
- 竞赛图专题突破 - Compound_Interest - 博客园
- 由竞赛图的分数序列构造出竞赛图 - yspm - 博客园
- 竞赛图小记 - 洛谷专栏