Codeforces 题目传送门 & 洛谷题目传送门

首先我们将所有十进制下位数相同的点看作一种颜色,这样题目转化为,给定 \(m\le 6\) 种颜色、每种颜色的点的个数 \(b_i\) 以及每两种颜色之间连的边的条数 \(c_{i,j}\),要求构造出一棵符合要求的树。

考虑怎样解决上面的问题,这里有一个结论,对于每种颜色我们钦定一个点为“关键点”(方便起见,对于颜色 \(i\),我们钦定 \(10^{i-1}\) 为第 \(i\) 种颜色的关键点),那么,如果存在合法的树,一定存在一种情况,使得任意一条边都有一个点为关键点。至于证明,不太会严谨证明,不过大概想想应该可以想通,大概就是对于每条边 \((u,v)\),如果 \(u,v\) 都不是关键点,那么可以将 \(u\) 改接到 \(v\) 的颜色的关键点,或者将 \(v\) 改接到 \(u\) 的颜色的关键点,总能找到一种调整方法使得不存在 \(u,v\) 都不是关键点的边 \((u,v)\)。

不难发现对于符合上面的条件的图,如果只考虑 \(m\) 个关键点,那么这 \(m\) 个点形成的图也是一棵 \(m\) 个点的树,由于 \(m\) 很小,因此考虑根据 prufer 序列将这 \(m^{m-2}\) 棵树枚举一遍,接下来考虑怎样检验对于一棵关键点的生成树,是否存在一种将非关键点连向关键点的方案,使得对于任意两种颜色 \(i,j\),\(i,j\) 之间连的边数恰为 \(c_{i,j}\),我们不妨将这个问题转化一下,可以得到如下的模型:

  • 对于每种颜色,共有 \(b_i-1\) 个非关键点,对于这 \(b_i-1\) 个关键点中的每一个点 \(u\),我们都要选择一种颜色 \(j\),并将 \(u\) 连向 \(j\) 的关键点,这样会使得 \(u,j\) 间边的个数多 \(1\)。
  • 对于每个颜色之间的二元组 \((i,j)\) 都还需连 \(a_{i,j}\) 条边,其中 \(a_{i,j}\) 为 \(c_{i,j}\) 减去 \(i,j\) 在枚举的生成树上是否存在边。

敏感的同学应该可以发现,这不就一个二分图多重匹配吗?我们将所有颜色对 \((i,j)\) 看作左部点,连一条从源点像这样的 \((i,j)\),容量为 \(a_{i,j}\) 的边,所有颜色 \(i\) 看作右部点,连一条从 \(i\) 到汇点,容量为 \(b_i-1\) 的边,然后检验这张图是否存在完备匹配即可。输出方案就 dinic 跑遍最大流即可。时间复杂度 \(\mathcal O(\text{能过})\)。

const int MAXV=30;
const int MAXE=300*2;
const int INF=0x3f3f3f3f;
int n,m,p[8],q[8],cnt[8];
int S=29,T=30,hd[MAXV+5],to[MAXE+5],nxt[MAXE+5],cap[MAXE+5],ec=1;
void init(){memset(hd,0,sizeof(hd));ec=1;}
void adde(int u,int v,int f){
to[++ec]=v;cap[ec]=f;nxt[ec]=hd[u];hd[u]=ec;
to[++ec]=u;cap[ec]=0;nxt[ec]=hd[v];hd[v]=ec;
} int dep[MAXV+5],now[MAXV+5];
bool getdep(){
memset(dep,-1,sizeof(dep));dep[S]=0;
queue<int> q;q.push(S);now[S]=hd[S];
while(!q.empty()){
int x=q.front();q.pop();
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(!~dep[y]&&z){
dep[y]=dep[x]+1;
q.push(y);now[y]=hd[y];
}
}
} return ~dep[T];
}
int getflow(int x,int f){
if(x==T) return f;int ret=0;
for(int &e=now[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(dep[y]==dep[x]+1&&z){
int w=getflow(y,min(f-ret,z));
cap[e]-=w;cap[e^1]+=w;ret+=w;
if(ret==f) return ret;
}
} return ret;
}
int dinic(){
int ret=0;
while(getdep()) ret+=getflow(S,INF);
return ret;
}
int num[8][8],cc[8][8],pru[8],deg[8],vis[8];
void solve(){
memset(deg,0,sizeof(deg));
memset(vis,0,sizeof(vis));
memset(cc,0,sizeof(cc));
for(int i=1;i<=m-2;i++) deg[pru[i]]++;
for(int i=1;i<=m-2;i++){
int pos=0;
for(int j=1;j<=m;j++){
if(!deg[j]&&!vis[j]){pos=j;break;}
} cc[min(pos,pru[i])][max(pos,pru[i])]++;
// eprintf("%d %d\n",pos,pru[i]);
deg[pru[i]]--;vis[pos]=1;
} int u1=1,u2=m;
while(vis[u1]) u1++;
while(vis[u2]) u2--;
cc[u1][u2]++;
// eprintf("%d %d\n",u1,u2);
int cur=0;init();
for(int i=1;i<=m;i++) for(int j=i;j<=m;j++){
if(cc[i][j]>num[i][j]) return;cur++;
adde(S,cur,num[i][j]-cc[i][j]);
adde(cur,m*(m+1)/2+i,INF);
adde(cur,m*(m+1)/2+j,INF);
} for(int i=1;i<=m;i++) adde(m*(m+1)/2+i,T,cnt[i]-1);
if(dinic()==n-m){
for(int i=1;i<=m;i++) for(int j=i;j<=m;j++){
if(cc[i][j]) printf("%d %d\n",p[i],p[j]);
}
for(int i=1;i<=m;i++) q[i]=p[i];cur=0;
for(int i=1;i<=m;i++) for(int j=i;j<=m;j++){
cur++;
for(int e=hd[cur];e;e=nxt[e]){
int y=to[e],z=cap[e^1];
if(y==S) continue;
if(y-m*(m+1)/2==i){
while(z--) printf("%d %d\n",++q[i],p[j]);
} else {
while(z--) printf("%d %d\n",++q[j],p[i]);
}
}
}
exit(0);
}
}
void dfs(int x){
if(x==m-1) return solve();
for(int i=1;i<=m;i++) pru[x]=i,dfs(x+1);
}
int main(){
scanf("%d",&n);for(int cur=1;cur<=n;cur*=10) p[++m]=cur;
for(int i=1;i<m;i++) cnt[i]=p[i+1]-p[i];cnt[m]=n-p[m]+1;
for(int i=1;i<n;i++){
static char s1[9],s2[9];
scanf("%s%s",s1+1,s2+1);
int l1=strlen(s1+1),l2=strlen(s2+1);
if(l1>l2) l1^=l2^=l1^=l2;
num[l1][l2]++;
} if(m==1){
if(num[1][1]!=n-1) return puts("-1"),0;
for(int i=1;i<n;i++) printf("%d %d\n",i,i+1);
return 0;
} dfs(1);puts("-1");
return 0;
}

Codeforces 611H - New Year and Forgotten Tree(二分图多重匹配)的更多相关文章

  1. hihoCoder 1393 网络流三·二分图多重匹配(Dinic求二分图最大多重匹配)

    #1393 : 网络流三·二分图多重匹配 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来. 小Hi和小H ...

  2. 【POJ 1698】Alice's Chance(二分图多重匹配)

    http://poj.org/problem?id=1698 电影和日子匹配,电影可以匹配多个日子. 最多有maxw*7个日子. 二分图多重匹配完,检查一下是否每个电影都匹配了要求的日子那么多. #i ...

  3. 稳定的奶牛分配 && 二分图多重匹配+二分答案

    题意: 农夫约翰有N(1<=N<=1000)只奶牛,每只奶牛住在B(1<=B<=20)个奶牛棚中的一个.当然,奶牛棚的容量有限.有些奶牛对它现在住的奶牛棚很满意,有些就不太满意 ...

  4. hiho 第117周 二分图多重匹配,网络流解决

    描述 学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来. 小Hi和小Ho作为班上的班干部,统计分配比赛选手的重任也自然交到了他们手上. 已知小Hi和小Ho所在的班级一共有N名学生(包含 ...

  5. 【网络流24题】No.7 试题库问题 (最大流,二分图多重匹配)

    [题意] 假设一个试题库中有 n 道试题. 每道试题都标明了所属类别. 同一道题可能有多个类别属性.现要从题库中抽取 m 道题组成试卷.并要求试卷包含指定类型的试题. 试设计一个满足要求的组卷算法. ...

  6. POJ2584 T-Shirt Gumbo【二分图多重匹配】

    题目链接: id=2584">http://poj.org/problem?id=2584 题目大意: 如今有5种型号(S.M.L.X.T)的衣服要发放给N个參赛队员.给出每一个參赛者 ...

  7. 网络流24题 第五题 - PowerOJ1740 CodeVS1905 圆桌问题 二分图多重匹配 网络最大流

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - PowerOJ1740 - 有SPJ - 推荐 题目传送门 - CodeVS1905 - 无SPJ - 0% ...

  8. [HihoCoder1393]网络流三·二分图多重匹配

    题目大意: 班级有$N$名学生,运动会有$M$项不同的比赛,第$i$项比赛每个班需要派出$m_i$名选手参加,编号为i的学生最多同时参加给定的$b_i$项比赛中的任意$a_i$项比赛.根据统计的结果, ...

  9. hdu3605 Escape 二分图多重匹配/最大流

    2012 If this is the end of the world how to do? I do not know how. But now scientists have found tha ...

随机推荐

  1. 初学python-day2 字符串格式化1

  2. 网络通信IO的演变过程(二)(一个门外汉的理解)

    2.NIO 当与别人谈论NIO时,一定要弄清楚别人说的NIO是指哪个含义? NIO有2种含义: 1.NonBlocking IO,基于操作系统谈 2.Java New IO,基于Java谈 我们这里主 ...

  3. nsq - 一条消息的生命周期(一)

    经过前面几篇的学习,相信大家对nsq已经有了一个大概的了解,我在写这篇文章的时候也看了很多其他人写的教程,发现大家对于分析系统每个点写的很不错,但是都很少有整体串起来一起走一遍,所以,我打算分成2-3 ...

  4. Coursera Deep Learning笔记 改善深层神经网络:优化算法

    笔记:Andrew Ng's Deeping Learning视频 摘抄:https://xienaoban.github.io/posts/58457.html 本章介绍了优化算法,让神经网络运行的 ...

  5. Noip模拟35 2021.8.10

    考试题目变成四道了,貌似确实根本改不完... 不过给了两个小时颓废时间确实很爽(芜湖--) 但是前几天三道题改着不是很费劲的时候为什么不给放松时间, 非要在改不完题的时候颓?? 算了算了不碎碎念了.. ...

  6. Pogo-Cow S

    这题出在单调队列优化dp里,就离谱好吧...... 对不住了上来先喷一波,不过离谱是确实的 dp的含义也很简单,就是说从j到i的分数最大值 直接上代马,里面说的很详细了 1 #include<b ...

  7. 震惊,本Orzer下阶段直接怒送四个笑脸

    众所周知,在hzoi帝国中,Wzx是最菜的.那么究竟有多菜呢?下面就和小编一起来看看吧. 近日,hzoi最菜的wzx在第四阶段竟然怒送4个笑脸,同机房神犇直呼wzx太菜了! 以上就是wzx第四阶段怒送 ...

  8. 2021.9.7考试总结[NOIP模拟49]

    T1 Reverse $BFS$暴力$O(n^2)$ 过程中重复枚举了很多点,考虑用链表记录当前点后面可到达的第一个未更新点. 搜索时枚举翻转子串的左端点,之后便可以算出翻转后$1$的位置. $cod ...

  9. 常用Java API:大数类

    摘要 java中的基础数据类型能存储的最大的二进制数是 2 ^ 63 - 1, 对应的十进制数是9223372036854775807,也就是说只要运算过程中会超过这个数,就会造成数据溢出,从而造成错 ...

  10. js计算精确度丢失问题解决

    (function () { var calc = { /* 函数,加法函数,用来得到精确的加法结果 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精 ...