zoukankan      html  css  js  c++  java
  • 藏宝图

     藏宝图

    时间限制: 2 Sec  内存限制: 256 MB

    题目描述

    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
    ");
     85             printf("1
    ");
     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
    ");
    111         }
    112         else{
    113             printf("Yes
    ");
    114             printf("%d
    ",sc);
    115         }
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    构建之法阅读笔记一
    第一冲刺阶段 工作总结 02
    第一冲刺阶段 工作总结 01
    学习进度条 第七周
    团队计划会议 01
    团队博客 一 需求分析
    学习进度条 第六周
    数组练习3 求最大连通子数组的和
    03构建之法阅读笔记之三
    团队项目个人每日总结(4.19)
  • 原文地址:https://www.cnblogs.com/FOXYY/p/7258161.html
Copyright © 2011-2022 走看看