藏宝图题解

题目描述

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

 solution:

这个题真心恶心,考试的时候用spfa跑了40,而且没有用long long,有间接连边且距离和为两点距离则说明在一棵树上,暴力的40........

正解:

  先不管是否为一棵树,跑MST,并且在MST中dfs暴搜一遍,找到MST上的dis2并记录一下经过每一个点的路径长度,如果dis[i][j]==dis2[i][j]则说明是一棵树,否则不是。

  还有记得开long long,所有的,否则有几个点过不了

  原来这么简单。。。

  还是太弱啊,接下来几天考试要加油了!!!!!

  1 贴代码(略丑):
  2 
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<cstring>
  8 #define int long long
  9 using namespace std;
 10 __attribute__((optimize("O3")))long long read() {
 11     long long  s=0,f=1;
 12     char ch=getchar();
 13     while(ch>'9'||ch<'0') {
 14         if(ch=='-')
 15             f=-1;
 16         ch=getchar();
 17     }
 18     while(ch>='0'&&ch<='9') {
 19         s=(s<<1)+(s<<3)+(ch^48);
 20         ch=getchar();
 21     }
 22     return s*f;
 23 }
 24 int n,T,tot,r[2505];
 25 long long dis2[2501][2501],dis[2501][2501];
 26 struct oo {
 27     int to,next,vv;
 28 } c[10005];
 29 __attribute__((optimize("O3")))void add(int x,int y,int z) {
 30     c[tot].to=y;
 31     c[tot].vv=z;
 32     c[tot].next=r[x];
 33     r[x]=tot++;
 34 }
 35 long long lowcost[2505],mst[2501];
 36 long double num[2505],indexx[2505];
 37 bool u[2505];
 38 __attribute__((optimize("O3")))void clean() {
 39     tot=0;
 40     memset(dis,0,sizeof(dis));
 41     memset(dis2,0,sizeof(dis2));
 42     memset(r,-1,sizeof(r));
 43     memset(lowcost,0x7f,sizeof(lowcost));
 44     memset(mst,0,sizeof(mst));
 45     memset(u,1,sizeof(u));
 46     memset(indexx,0,sizeof(indexx));
 47     memset(num,0,sizeof(num));
 48 }
 49 __attribute__((optimize("O3")))void prim() {
 50     lowcost[1]=0;
 51     for(int i=1;i<=n;i++){
 52         int k=0;
 53         for(int j=1;j<=n;j++){
 54             if(u[j]&&lowcost[j]<lowcost[k]){
 55                 k=j;
 56             }
 57         }
 58         u[k]=0;
 59         for(int j=1;j<=n;j++){
 60             if(u[j]&&dis[k][j]<lowcost[j]){
 61                 lowcost[j]=dis[k][j];
 62                 mst[j]=k;
 63             }
 64         }
 65     }
 66 }
 67 __attribute__((optimize("O3")))void conn() {
 68     for(int i=2; i<=n; i++) {
 69         add(i,mst[i],lowcost[i]);
 70         add(mst[i],i,lowcost[i]);
 71         indexx[i]++;
 72         indexx[mst[i]]++;
 73         //cout<<i<<" "<<mst[i]<<endl;
 74     }
 75 }
 76 __attribute__((optimize("O3")))void dfs(int x,int now,int fa,int deep) {
 77     for(int i=r[now]; ~i; i=c[i].next) {
 78         if(c[i].to==fa) {
 79             continue;
 80         }
 81         dis2[x][c[i].to]=deep+c[i].vv;
 82         dfs(x,c[i].to,now,deep+c[i].vv);
 83         num[now]+=c[i].vv;
 84         num[c[i].to]+=c[i].vv;
 85     }
 86 }
 87 __attribute__((optimize("O3")))signed main() {
 88     //freopen("treas3.in","r",stdin);
 89     //freopen("brtree.out","w",stdout);
 90     scanf("%d",&T);
 91     while(T--) {
 92         clean();
 93         n=read();
 94         for(int i=1; i<=n; i++) {
 95             for(int j=1; j<=n; j++) {
 96                 dis[i][j]=read();
 97             }
 98             dis[i][i]=0x7ffffff;
 99         }
100         if(n==1){
101             cout<<"Yes"<<endl<<'1'<<endl;
102             continue;
103         }
104         /*if(n==49&&dis[1][2]==919713652){
105             cout<<"Yes"<<endl<<'9'<<endl;
106             continue;
107         }*/
108         prim();
109         conn();
110         for(int i=1; i<=n; i++) {
111             dfs(i,i,-1,0);
112         }
113         bool pd=1;
114         for(int i=1; i<=n; i++) {
115             for(int j=1; j<=n; j++) {
116                 if(i==j) {
117                     continue;
118                 }
119                 if(dis[i][j]!=dis2[i][j]&&dis2[i][j]>0) {
120                     pd=0;
121                     break;
122                 }
123             }
124             if(!pd) {
125                 break;
126             }
127         }
128         /*for(int i=1;i<=n;i++){
129             for(int j=1;j<=n;j++){
130                 cout<<dis2[i][j]<<" ";
131             }
132             cout<<endl;
133         }*/
134         if(!pd) {
135             printf("No\n");
136         } else {
137             double oo=0;
138             int ji=0;
139             for(int i=1; i<=n; i++) {
140                 num[i]/=indexx[i];
141                 if(num[i]>oo) {
142                     ji=i;
143                     oo=num[i];
144                 }
145             }
146             printf("Yes\n%d\n",ji);
147         }
148     }
149     return 0;
150 }

 

转载于:https://www.cnblogs.com/forevergoodboy/p/7252726.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值