cf472D Design Tutorial: Inverse the Problem
2 seconds
256 megabytes
standard input
standard output
There is an easy way to obtain a new task from an old one called "Inverse the problem": we give an output of the original task, and ask to generate an input, such that solution to the original problem will produce the output we provided. The hard task of Topcoder Open 2014 Round 2C, InverseRMQ, is a good example.
Now let's create a task this way. We will use the task: you are given a tree, please calculate the distance between any pair of its nodes. Yes, it is very easy, but the inverse version is a bit harder: you are given an n × n distance matrix. Determine if it is the distance matrix of a weighted tree (all weights must be positive integers).
The first line contains an integer n (1 ≤ n ≤ 2000) — the number of nodes in that graph.
Then next n lines each contains n integers di, j (0 ≤ di, j ≤ 109) — the distance between node i and node j.
If there exists such a tree, output "YES", otherwise output "NO".
- 3
- 0 2 7
- 2 0 9
- 7 9 0
- YES
- 3
- 1 2 7
- 2 0 9
- 7 9 0
- NO
- 3
- 0 2 2
- 7 0 9
- 7 9 0
- NO
- 3
- 0 1 1
- 1 0 1
- 1 1 0
- NO
- 2
- 0 0
- 0 0
- NO
In the first example, the required tree exists. It has one edge between nodes 1 and 2 with weight 2, another edge between nodes 1 and 3 with weight 7.
In the second example, it is impossible because d1, 1 should be 0, but it is 1.
In the third example, it is impossible because d1, 2 should equal d2, 1.
我对于暴力出奇迹又有了更深的理解……
题意是给你一个dist[i][j]的邻接矩阵,判断这是不是一棵树。
想法是先假设这就是棵树,用最小生成树直接算出应有的n-1条边,然后暴力求出在只有这n-1条边的情况下的dist和原数组比较
当然前面还要预处理排除一堆不合法答案
hzwer:为什么要做最小生成树呢?因为首先距离当前点x最近的点y肯定是有边直接连接的,因为(反证法)假设有z使得xz和yz分别连接,则dis[x][z]+dis[y][z]<=dis[x][y],所以应该有dis[x][z]<dis[x][y],与已知条件dist[x][y]最小不符
所以我们要优先考虑边权小的边,所以直接最小生成树
这题n=2000就是400w的边,再加点处理也有200w边,明显稠密图,应该用Prim,居然Kruskal能过……服了
贴代码……
以下Kruskal版
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<algorithm>
- #include<cmath>
- #include<queue>
- #include<deque>
- #include<set>
- #include<map>
- #include<ctime>
- #define LL long long
- #define inf 2147483647
- #define pa pair<int,int>
- #define N 2100
- using namespace std;
- struct bian{
- int x,y,z;
- }b[2000010];
- bool operator < (const bian &a,const bian &b)
- {
- return a.z<b.z;
- }
- struct edge{
- int to,next,v;
- }e[10*N];int head[N];
- LL n,cnt,tot;
- LL a[N][N];
- int fa[N];
- int top,zhan[N];bool vis[N];
- LL dist[N][N];
- inline int getfa(int x)
- {return fa[x]==x?x:fa[x]=getfa(fa[x]);}
- inline void ins(int u,int v,int w)
- {
- e[++cnt].to=v;
- e[cnt].next=head[u];
- e[cnt].v=w;
- head[u]=cnt;
- }
- inline void insert(int u,int v,int w)
- {
- ins(u,v,w);
- ins(v,u,w);
- }
- inline LL read()
- {
- LL x=0,f=1;char ch=getchar();
- while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
- while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
- return x*f;
- }
- inline void init()
- {
- n=read();
- for (int i=1;i<=n;i++)
- for (int j=1;j<=n;j++)
- a[i][j]=read();
- }
- inline bool pre_judge()
- {
- for (int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- {
- if (i==j&&a[i][i]!=0)return 0;
- if (i!=j&&a[i][j]==0)return 0;
- if (a[i][j]!=a[j][i])return 0;
- }
- return 1;
- }
- inline void Kruskal()
- {
- for (int i=1;i<=n;i++)fa[i]=i;
- for (int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- if (i<j)
- {
- b[++tot].x=i;
- b[tot].y=j;
- b[tot].z=a[i][j];
- }
- sort(b+1,b+tot+1);
- int piece=n;
- for (int i=1;i<=tot;i++)
- {
- int fx=getfa(b[i].x);
- int fy=getfa(b[i].y);
- if (fx==fy)continue;
- piece--;
- fa[fx]=fy;
- insert(b[i].x,b[i].y,b[i].z);
- if (piece==1)return;
- }
- }
- inline void dfs(int cur)
- {
- for (int i=head[cur];i;i=e[i].next)
- {
- if (vis[e[i].to])continue;
- for (int j=1;j<=top;j++)
- {
- dist[e[i].to][zhan[j]]=dist[zhan[j]][e[i].to]=dist[zhan[j]][cur]+e[i].v;
- }
- zhan[++top]=e[i].to;
- vis[e[i].to]=1;
- dfs(e[i].to);
- }
- }
- int main()
- {
- init();
- if (!pre_judge())
- {
- printf("NO");
- return 0;
- }
- Kruskal();
- zhan[1]=1;top=1;vis[1]=1;
- dfs(1);
- for (int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- if(a[i][j]!=dist[i][j])
- {
- printf("NO");
- return 0;
- }
- printf("YES");
- return 0;
- }
以下Prim版(第一次写,有点锉,神犇别D我)
- #include<cstdio>
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<algorithm>
- #include<cmath>
- #include<queue>
- #include<deque>
- #include<set>
- #include<map>
- #include<ctime>
- #define LL long long
- #define inf 2147483647
- #define pa pair<int,int>
- #define N 2100
- using namespace std;
- struct edge{
- int to,next,v;
- }e[10*N];int head[N];
- LL n,cnt;
- LL a[N][N];//读入的距离
- bool inset[N];//是否在MST集合中
- pa dis[N]; //二元组dist[k]=(i,j)表示从所有在集合中的点到k的最短边是从j到k,权为=i
- int top,zhan[N];bool vis[N];//MST之后处理dist的dfs用
- LL dist[N][N];//最后算出来的dist
- inline void ins(int u,int v,int w)
- {
- e[++cnt].to=v;
- e[cnt].next=head[u];
- e[cnt].v=w;
- head[u]=cnt;
- }
- inline void insert(int u,int v,int w)
- {
- ins(u,v,w);
- ins(v,u,w);
- }
- inline LL read()
- {
- LL x=0,f=1;char ch=getchar();
- while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
- while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
- return x*f;
- }
- inline bool pre_judge()
- {
- for (int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- {
- if (i==j&&a[i][i]!=0)return 0;
- if (i!=j&&a[i][j]==0)return 0;
- if (a[i][j]!=a[j][i])return 0;
- }
- return 1;
- }
- inline void init()
- {
- n=read();
- for (int i=1;i<=n;i++)
- for (int j=1;j<=n;j++)
- a[i][j]=read();
- }
- inline void prim()
- {
- int cur=1;inset[1]=1;
- for (int i=2;i<=n;i++)
- {
- dis[i].first=a[1][i];
- dis[i].second=1;
- }
- for (int i=1;i<n;i++)
- {
- LL mn=inf;
- int from=0;
- for (int j=1;j<=n;j++)
- if (!inset[j]&&dis[j].first<mn)
- {
- mn=dis[j].first;
- from=dis[j].second;
- cur=j;
- }
- insert(from,cur,mn);
- inset[cur]=1;
- for (int j=1;j<=n;j++)
- if (!inset[j]&&a[cur][j]<dis[j].first)
- {
- dis[j].first=a[cur][j];
- dis[j].second=cur;
- }
- }
- }
- inline void dfs(int cur)
- {
- for (int i=head[cur];i;i=e[i].next)
- {
- if (vis[e[i].to])continue;
- for (int j=1;j<=top;j++)
- {
- dist[e[i].to][zhan[j]]=dist[zhan[j]][e[i].to]=dist[zhan[j]][cur]+e[i].v;
- }
- zhan[++top]=e[i].to;
- vis[e[i].to]=1;
- dfs(e[i].to);
- }
- }
- int main()
- {
- init();
- if (!pre_judge())
- {
- printf("NO");
- return 0;
- }
- prim();
- zhan[1]=1;top=1;vis[1]=1;
- dfs(1);
- for (int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- if(a[i][j]!=dist[i][j])
- {
- printf("NO");
- return 0;
- }
- printf("YES\n");
- return 0;
- }
cf472D Design Tutorial: Inverse the Problem的更多相关文章
- D. Design Tutorial: Inverse the Problem 解析含快速解法(MST、LCA、思維)
Codeforce 472D Design Tutorial: Inverse the Problem 解析含快速解法(MST.LCA.思維) 今天我們來看看CF472D 題目連結 題目 給你一個\( ...
- 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 ...
- Design Tutorial: Inverse the Problem
Codeforces Round #270 D:http://codeforces.com/contest/472/problem/D 题意:给以一张图,用邻接矩阵表示,现在问你这张图能不能够是一棵树 ...
- codeforces D. Design Tutorial: Inverse the Problem
题意:给定一个矩阵,表示每两个节点之间的权值距离,问是否可以对应生成一棵树, 使得这棵树中的任意两点之间的距离和矩阵中的对应两点的距离相等! 思路:我们将给定的矩阵看成是一个图,a 到 b会有多条路径 ...
- Codeforces Round #270 D Design Tutorial: Inverse the Problem --MST + DFS
题意:给出一个距离矩阵,问是不是一颗正确的带权树. 解法:先按找距离矩阵建一颗最小生成树,因为给出的距离都是最短的点间距离,然后再对每个点跑dfs得出应该的dis[][],再对比dis和原来的mp是否 ...
- 【CF】270D Design Tutorial: Inverse the Problem
题意异常的简单.就是给定一个邻接矩阵,让你判定是否为树.算法1:O(n^3).思路就是找到树边,原理是LCA.判断树边的数目是否为n-1.39-th个数据T了,自己测试2000跑到4s.算法2:O(n ...
- cf472C Design Tutorial: Make It Nondeterministic
C. Design Tutorial: Make It Nondeterministic time limit per test 2 seconds memory limit per test 256 ...
- cf472B Design Tutorial: Learn from Life
B. Design Tutorial: Learn from Life time limit per test 1 second memory limit per test 256 megabytes ...
- cf472A Design Tutorial: Learn from Math
A. Design Tutorial: Learn from Math time limit per test 1 second memory limit per test 256 megabytes ...
随机推荐
- ACM1174_爆头解题思路_空间三维坐标求点到直线的距离
/* 爆头 Description gameboy是一个CS高手,他最喜欢的就是扮演警察, 手持M4爆土匪的头.也许这里有人没玩过CS,有必 要介绍一下“爆头”这个术语:所谓爆头,就是子 弹直接命中对 ...
- Javascript常用正则表达式
一.校验数字的表达式 数字:^[0-9]*$ n位的数字:^\d{n}$ 至少n位的数字:^\d{n,}$ m-n位的数字:^\d{m,n}$ 零和非零开头的数字:^(0|[1-9][0-9]*)$ ...
- [每日一题] 11gOCP 1z0-052 :2013-09-4 block header grows............................................A33
转载请注明出处:http://write.blog.csdn.net/postedit/11100311 正确答案是:AD 要理解这道题就要去了解数据块的结构.引用OCPPPT中的一幅图: 从这幅图中 ...
- 利用Unicorn和Idaemu辅助解决Geekpwn SecretCode
在前面的些文章里,我提到了怎么交叉编译Unicorn-engine,以及在windows上使用Unicorn python bindings进行分析程序.这一次我介绍下如何使用Unicorn-engi ...
- SVG Loading
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="64&qu ...
- OutputCache各参数的说明
OutputCache各参数的说明 Duration 缓存时间,以秒为单位,这个除非你的Location=None,可以不添加此属性,其余时候都是必须的. Location Location当被设置为 ...
- hadoop启动守护进程报JAVA_HOME is not set and could not be found
hadoop启动守护进程 sbin/start-dfs.sh 报如下错误:JAVA_HOME is not set and could not be found 解决办法(JAVA_HOME修改为具体 ...
- 嵌入式Linux LED小灯点亮实验
问:怎么写LED驱动程序? 1.搭建一个字符驱动的框架(上一节已经完成) 2.完善硬件的操作 问:驱动里操作硬件寄存器与单片机操作硬件寄存器有什么不一样的地方? 答:单片机操作的寄存器地址是物理地址, ...
- codeforces 340E Iahub and Permutations(错排or容斥)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Iahub and Permutations Iahub is so happy ...
- sql 列设置默认值,语法查询知识点积累
一.修改字段默认值 alter table 表名 drop constraint 约束名字 ------说明:删除表的字段的原有约束 alter table 表名 add constraint 约 ...