Codeforce 472D Design Tutorial: Inverse the Problem 解析含快速解法(MST、LCA、思維)

今天我們來看看CF472D

題目連結

題目

給你一個\(n\times n\)的矩陣代表點\(i\)到點\(j\)的最短距離。問是否可以造出一棵邊權為正的樹。

前言

這題的輸入,輸入3e6個Integer經過實測就大概需要700ms以上了(如果沒開輸入優化好像還會直接TLE的樣子)。並且我一開始是用Prim's Algo去寫MST的,priority_queue用class來對pair<int,int> overload compare function,結果不管怎麼弄都TLE。最後放棄使用pair<int,int>,直接創一個struct,就AC了...。

看來Prim這種東西不但常數大,碰上一些奇怪的問題的機率還比較高阿...(EDIT:之後我在其他題目發現,如果把queue<element> q;宣告在非全域,那麼很有可能只要改動例如陣列size這種無關緊要的地方,就會造成TLE,當時的情況是每次bfs都在local宣告一次queue<element> q;)

乖乖用Kruskal就好了吧

(以下提供兩種方法的code)

想法

假設目前你只獲得了部分的樹(還有點沒有在樹裡面),那麼這棵樹到那些還沒加入的點的最短距離「中」的最短的,必定是一條存在的連出去的邊,那麼我們當然需要把這條邊加進去。

以上的討論可以發現,這恰好就是Prim's Algo的過程阿!也就是這棵樹就是一個最小生成樹。

那我們可以選用兩種方法來造出這棵樹(Kruskal,Prim)。

剩下就是把最短路徑的矩陣造出來並且比對是否正確就好(使用LCA找到正確的路徑,並且記錄root到每個點的距離(也就是前綴和),如此就可以\(O(\lg n)\)算出最短距離了)。

想法2

這個想法網路上好像沒有人寫,但是比賽時很多人都是這樣寫的,很快。

首先確認\(i\rightarrow i\)的距離是\(0\)、\(i\rightarrow j,\ i\neq j\)的距離不為\(0\)、\(dis(i\rightarrow j)==dis(j\rightarrow i)\)。

接著沿用想法一,我們知道MST是存在的,而我們有的資訊只有那\(n\times n\)的距離矩陣,接下來只要測試任何邊(u,v)這條邊是可以在樹上就好(由於我們擁有的資訊只有這\(n\times n\)的矩陣,所以我們只要確認所有經過(u,v)的路徑都可以如矩陣上那樣就好),最後只要把全部的(u,v) pair都測試過一遍,就結束了。

(這段話寫得比較模糊,建議直接看code)

程式碼(想法二):

const int _n=2010;
int t,n,d[_n][_n];
main(void) {cin.tie(0);ios_base::sync_with_stdio(0);
cin>>n;rep(i,1,n+1)rep(j,1,n+1)cin>>d[i][j];
rep(i,1,n+1)rep(j,i,n+1)if((i==j and d[i][i]) or d[i][j]!=d[j][i] or (i!=j and d[i][j]==0)){cout<<"NO\n";return 0;}
rep(i,1,n+1){
int r=1;
rep(j,2,n+1)if(i!=j and d[r][i]>d[j][i])r=j;
rep(k,1,n+1)if(abs(d[k][i]-d[k][r])!=d[i][r]){cout<<"NO\n";return 0;}
}cout<<"YES\n";
return 0;
}

標頭、模板請點codepad看

Submission

程式碼(Kruskal):

const int _n=2010,MAXB=12;
int parent[_n], rank[_n];
inline void dsinit(int n) {for (int i = 0; i < n; i++)parent[i] = i;memset(rank, 0, sizeof rank);}
inline int dsfind(int e) {return parent[e] == e ? e : parent[e] = dsfind(parent[e]);}
inline void dsunion(int s1, int s2) {if (rank[s1] < rank[s2])swap(s1, s2);parent[s2] = s1;if (rank[s1] == rank[s2]) rank[s1]++;}
//以上是dsu模板
int t,n,dep[_n],fa[_n][MAXB],d[_n][_n];
ll dis[_n];
vector<PII> G[_n];
struct E{
int f,t,w;
bool operator<(const E& rhs) const {return w<rhs.w;}
};
vector<E> e;
bool vis[_n];
void dfs(int v,int faa,ll len){
dep[v]=dep[faa]+1;dis[v]=dis[faa]+len;fa[v][0]=faa;
rep(i,0,SZ(G[v]))if(faa!=G[v][i].fi)dfs(G[v][i].fi,v,G[v][i].se);
}
void bfa(){
rep(j,1,MAXB)rep(i,1,n+1)if(~fa[i][j-1])
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
per(j,0,MAXB)if(~fa[a][j] and dep[fa[a][j]]>=dep[b])a=fa[a][j];
if(a==b)return a;
per(j,0,MAXB)if(~fa[a][j] and fa[a][j]!=fa[b][j])a=fa[a][j],b=fa[b][j];
return fa[a][0];
}
//以上基本上是lca模板
main(void) {cin.tie(0);ios_base::sync_with_stdio(0);
cin>>n;rep(i,1,n+1)rep(j,1,n+1)cin>>d[i][j];
rep(i,1,n+1)rep(j,i,n+1)if((i==j and d[i][i]) or d[i][j]!=d[j][i] or (i!=j and d[i][j]==0)){cout<<"NO\n";return 0;}
rep(i,1,n+1)rep(j,i+1,n+1)e.pb({i,j,d[i][j]}); sort(all(e)); dsinit(n);
rep(i,0,SZ(e)){
int s1=dsfind(e[i].f),s2=dsfind(e[i].t);
if(s1==s2) continue;
dsunion(s1,s2);
G[e[i].f].pb({e[i].t,e[i].w});
G[e[i].t].pb({e[i].f,e[i].w});
}
dep[0]=-1;dfs(1,0,0);rep(i,1,n+1)rep(j,1,MAXB)fa[i][j]=-1; bfa();
rep(i,1,n+1)rep(j,i,n+1){
int l=lca(i,j);
if(d[i][j]!=dis[i]+dis[j]-dis[l]*2){cout<<"NO\n";return 0;}
}cout<<"YES\n";
return 0;
}

標頭、模板請點Submission看

Submission

程式碼(Prim's):

const int _n=2010,MAXB=13;
int t,n,dep[_n],fa[_n][MAXB];
ll d[_n][_n],dis[_n];
vector<PII> G[_n];
bool vis[_n];
struct node{
int f,t,w;
bool operator<(const node& rhs) const {return w>rhs.w;}
};
//以上是真正有用到的struct
class Cmp{
public:
bool operator()(const PII& a,const PII& b) const {return d[a.fi][a.se]>d[b.fi][b.se];}
};
//以上class,如前言所說,會造成TLE
void dfs(int v,int faa,ll len){
dep[v]=dep[faa]+1;dis[v]=dis[faa]+len;fa[v][0]=faa;
rep(i,0,SZ(G[v]))if(faa!=G[v][i].fi)dfs(G[v][i].fi,v,G[v][i].se);
}
void bfa(){
rep(j,1,MAXB)rep(i,1,n+1)if(~fa[i][j-1])
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
per(j,0,MAXB)if(~fa[a][j] and dep[fa[a][j]]>=dep[b])a=fa[a][j];
if(a==b)return a;
per(j,0,MAXB)if(~fa[a][j] and fa[a][j]!=fa[b][j])a=fa[a][j],b=fa[b][j];
return fa[a][0];
}
//以上基本上是lca模板
main(void) {cin.tie(0);ios_base::sync_with_stdio(0);
cin>>n;rep(i,1,n+1)rep(j,1,n+1)cin>>d[i][j];
rep(i,1,n+1)rep(j,i,n+1)if((i==j and d[i][i]) or d[i][j]!=d[j][i] or (i!=j and d[i][j]==0)){cout<<"NO\n";return 0;}
priority_queue<node> pq;
pq.push({0,1});
while(!pq.empty()){
/*PII now;while(!pq.empty() and vis[(now=pq.top()).se])pq.pop();
if(pq.empty())break;*/
node now=pq.top(); pq.pop();
if(vis[now.t])continue;
vis[now.t]=1;
G[now.f].pb({now.t,d[now.f][now.t]});
//if(now.fi!=0)G[now.se].pb({now.fi,d[now.se][now.fi]});
rep(i,1,n+1)if(!vis[i])pq.push({now.t,i,d[now.t][i]});
}
dep[0]=-1;dfs(1,0,0);rep(i,1,n+1)rep(j,1,MAXB)fa[i][j]=-1; bfa();
rep(i,1,n+1)rep(j,i,n+1){
int l=lca(i,j);
if(d[i][j]!=dis[i]+dis[j]-dis[l]*2){cout<<"NO\n";return 0;}
}cout<<"YES\n";
return 0;
}

標頭、模板請點Submission看

Submission

D. Design Tutorial: Inverse the Problem 解析含快速解法(MST、LCA、思維)的更多相关文章

  1. Codeforces #270 D. Design Tutorial: Inverse the Problem

    http://codeforces.com/contest/472/problem/D D. Design Tutorial: Inverse the Problem time limit per t ...

  2. cf472D Design Tutorial: Inverse the Problem

    D. Design Tutorial: Inverse the Problem time limit per test 2 seconds memory limit per test 256 mega ...

  3. Design Tutorial: Inverse the Problem

    Codeforces Round #270 D:http://codeforces.com/contest/472/problem/D 题意:给以一张图,用邻接矩阵表示,现在问你这张图能不能够是一棵树 ...

  4. codeforces D. Design Tutorial: Inverse the Problem

    题意:给定一个矩阵,表示每两个节点之间的权值距离,问是否可以对应生成一棵树, 使得这棵树中的任意两点之间的距离和矩阵中的对应两点的距离相等! 思路:我们将给定的矩阵看成是一个图,a 到 b会有多条路径 ...

  5. Codeforces Round #270 D Design Tutorial: Inverse the Problem --MST + DFS

    题意:给出一个距离矩阵,问是不是一颗正确的带权树. 解法:先按找距离矩阵建一颗最小生成树,因为给出的距离都是最短的点间距离,然后再对每个点跑dfs得出应该的dis[][],再对比dis和原来的mp是否 ...

  6. 【CF】270D Design Tutorial: Inverse the Problem

    题意异常的简单.就是给定一个邻接矩阵,让你判定是否为树.算法1:O(n^3).思路就是找到树边,原理是LCA.判断树边的数目是否为n-1.39-th个数据T了,自己测试2000跑到4s.算法2:O(n ...

  7. cf472C Design Tutorial: Make It Nondeterministic

    C. Design Tutorial: Make It Nondeterministic time limit per test 2 seconds memory limit per test 256 ...

  8. cf472B Design Tutorial: Learn from Life

    B. Design Tutorial: Learn from Life time limit per test 1 second memory limit per test 256 megabytes ...

  9. cf472A Design Tutorial: Learn from Math

    A. Design Tutorial: Learn from Math time limit per test 1 second memory limit per test 256 megabytes ...

随机推荐

  1. xshell评估过期(已解决)

    登录英文版官网 https://www.netsarang.com/ 点击download  选择xshell 5 . 直接在页面中有红色*号的地方输入个人信息,licensetype 必须选 Hom ...

  2. (转)Java中的值传递和引用传递

    Java中的值传递和引用传递 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?     答:是值传递.Java 编程语言只有值 ...

  3. Linux MMC 驱动子系统简述(源码剖析)

    1. Linux MMC 驱动子系统 块设备是Linux系统中的基础外设之一,而 MMC/SD 存储设备是一种典型的块设备.Linux内核设计了 MMC子系统,用于管理 MMC/SD 设备. MMC ...

  4. Python-去除字符串中不想要的字符

    问题: 过滤用户输入中前后多余的空白字符 '    ++++abc123---    ' 过滤某windows下编辑文本中的'\r': 'hello world \r\n' 去掉文本中unicode组 ...

  5. 面试官:开发过Maven插件吗?我:开发过啊。。。

    写在前面 转眼间,今天已经是假期的第4天了.今天要给大家分享点啥呢?想了半天,想起了之前去某宝面试的情景.记得面试前自己基于Maven开发过一些简单实用的插件,而且在自己的本地环境中一直在使用,极大的 ...

  6. python中numpy.savetxt 参数

    转载:https://blog.csdn.net/qq_36535820/article/details/99543188 numpy.savetxt 参数 numpy.savetxt(fname,X ...

  7. SPI通信基础学习

    SPI是"Serial Peripheral Interface"的缩写,即"串行外设接口",是摩托罗拉公司推出的一种串行接口通信协议. 接线的示意图: SPI ...

  8. 用于编写下一代JavaScript的编译器。

    下载 用于编写下一代JavaScript的编译器. 支持巴别塔 Babel(发音为babble)是一个由社区驱动的项目,被许多公司和项目使用,由一群志愿者维护.如果你愿意帮助支持这个项目的未来,请考虑 ...

  9. 视频+图文教程 | Java之安装JDK与环境配置

    演示所用软件JDK 8与Eclipse(Java开发工具)软件下载链接: 链接:https://pan.baidu.com/s/1Vg9ulrQH8WlGRAE89Y02UA提取码:swwl 视频介绍 ...

  10. Python+Appium自动化测试(14)-yaml配置Desired capabilities

    一,前言 在之前的appium自动化测试示例中,我们都是把构造driver实例对象的数据(即Desired Capabilities)写在业务代码里,如下: # -*- coding:utf-8 -* ...