藏宝图
时间限制: 2 Sec 内存限制: 256 MB
提交: 76 解决: 31
[提交][状态][讨论版]
题目描述
Czy爬上黑红树,到达了一个奇怪的地方……
Czy发现了一张奇怪的藏宝图。图上有n个点,m条无向边。已经标出了图中两两之间距离dist。但是czy知道,只有当图刚好又是一颗树的时候,这张藏宝图才是真的。如果藏宝图是真的,那么经过点x的边的边权平均数最大的那个x是藏着宝物的地方。请计算这是不是真的藏宝图,如果是真的藏宝之处在哪里。
输入
输入数据第一行一个数T,表示T组数据。
对于每组数据,第一行一个n,表示藏宝图上的点的个数。
接下来n行,每行n个数,表示两两节点之间的距离。
输出
输出一行或两行。第一行”Yes”或”No”,表示这是不是真的藏宝图。
若是真的藏宝图,第二行再输出一个数,表示哪个点是藏宝之处。
样例输入
2 3 0 7 9 7 0 2 9 2 0 3 0 2 7 2 0 9 7 9 0
样例输出
Yes 1 Yes 3 样例解释:第一棵树的形状是1--2--3。1、2之间的边权是7,2、3之间是2。 第二棵树的形状是2--1--3。2、1之间的边权是2,1、3之间是7。
提示
对于30%数据,n<=50,1<=树上的边的长度<=10^9。
对于50%数据,n<=600.
对于100%数据,1<=n<=2500,除30%小数据外任意0<=dist[i][j]<=10^9,T<=5
开始就没看懂题目,以为题目中给的是两个点之间直接连边的边权,然后就一直想不出来怎么着就不是一棵树,但其实图中给的是两个点之间的距离,那么,如果他是一棵树的话,这个距离是一定的,不可能存在更短的路径,因为在树中,两个点之间的路径是唯一的,若两个点之间的路径能被其他的点更新,那么就不是一棵树,因为两个点之间存在两条长度不同的路径,那么用prim跑一遍,得出最小生成树,在用这棵树去还原一个新的矩阵,若和原来的矩阵同,则yes,否则no,至于是某个点,随便搞都行
因为这道题点数比较少,而边很密,所以用Kruska会被卡
1 #include<cmath> 2 #include<ctime> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 using namespace std; 9 int T,n; 10 long long dis[2510][2510]; 11 long long ju[2510]; 12 bool vis[2510]; 13 int fa[2510]; 14 struct node{ 15 int u,v,nxt,w; 16 }g[5010]; 17 int adj[5010],e; 18 void add(int u,int v,int w){ 19 g[++e].v=v; g[e].u=u; g[e].w=w; 20 g[e].nxt=adj[u]; adj[u]=e; 21 } 22 void prim(){ 23 ju[1]=0; 24 for(int i=1;i<=n;i++){ 25 int k=0; 26 for(int j=1;j<=n;j++){ 27 if(!vis[j] && ju[j]<ju[k]) 28 k=j; 29 } 30 vis[k]=1; 31 for(int j=1;j<=n;j++){ 32 if(!vis[j] && dis[k][j]<ju[j]) 33 ju[j]=dis[k][j],fa[j]=k; 34 } 35 } 36 } 37 long long dis2[2510][2510],ji; 38 double mx=0; 39 int sc; 40 void clear(){ 41 memset(vis,0,sizeof(vis)); 42 memset(ju,0x7f,sizeof(ju)); 43 //cout<<ju[1]<<endl;; 44 memset(fa,0,sizeof(fa)); 45 e=0; mx=0; 46 memset(adj,0,sizeof(adj)); 47 48 } 49 void dfs(int x,long long sum,int num){ 50 //cout<<"ji== "<<ji<<" "<<x<<" "<<sum<<" "<<num<<endl; 51 dis2[ji][x]=sum; 52 vis[x]=1; 53 int chu; 54 if(x==ji) chu=0; 55 else chu=1; 56 double he=(double)num; 57 for(int i=adj[x];i;i=g[i].nxt){ 58 int v=g[i].v; 59 if(vis[v]) continue; 60 chu++; 61 dfs(v,sum+g[i].w,g[i].w); 62 he+=g[i].w; 63 } 64 he=he/(double)chu; 65 if(he>mx){ 66 mx=he; 67 sc=x; 68 } 69 } 70 int main(){ 71 //freopen("a.in","r",stdin); 72 //freopen("a.out","w",stdout); 73 scanf("%d",&T); 74 while(T--){ 75 scanf("%d",&n); 76 clear(); 77 for(int i=1;i<=n;i++){ 78 for(int j=1;j<=n;j++){ 79 scanf("%lld",&dis[i][j]); 80 //cout<<dis[i][j]<<endl; 81 } 82 } 83 if(n==1){ 84 printf("Yes\n"); 85 printf("1\n"); 86 continue; 87 } 88 prim(); 89 for(int i=2;i<=n;i++){ 90 add(fa[i],i,ju[i]); 91 add(i,fa[i],ju[i]); 92 } 93 /* 94 for(int i=1;i<=n;i++){ 95 cout<<"i== "<<i<<" "<<fa[i]<<endl; 96 }*/ 97 for(int i=1;i<=n;i++){ 98 memset(vis,0,sizeof(vis)); 99 vis[i]=1; ji=i; 100 dfs(i,0,0); 101 } 102 //while(1); 103 bool ok=1; 104 for(int i=1;i<=n;i++){ 105 for(int j=1;j<=n;j++){ 106 if(dis2[i][j] != dis[i][j]) ok=0; 107 } 108 } 109 if(!ok){ 110 printf("No\n"); 111 } 112 else{ 113 printf("Yes\n"); 114 printf("%d\n",sc); 115 } 116 } 117 return 0; 118 }
时间: 2024-10-23 04:39:24