题解:CF42D Strange town

· · 题解

思路

``` 0 1 2 1 0 3 2 3 0 ``` 满足要求。 我们不妨尝试每一次在原图新增一个结点,并求出满足条件的图。 $n=4$ 或 $n=5$ 时,可以设新增的几条边,解方程组。 $n=4$ 时,解得 $\begin{cases}y=x+1\\z=x+2\end{cases}$,邻接矩阵则为 ``` 0 1 2 4 1 0 3 5 2 3 0 6 4 5 6 0 ``` $n=5$ 时,解得 $\begin{cases}y=x+1\\z=x+2\\w=x+4\end{cases}$,邻接矩阵则为 ``` 0 1 2 4 7 1 0 3 5 8 2 3 0 6 9 4 5 6 0 11 7 8 9 11 0 ``` 通过观察点连出的旧边权之和与新增边的关系,发现结点 $k$ 与新节点连的边权和节点 $k$ 的旧边权之和之间存在着线性关系。 通过进一步的推算发现,设当前新增第 $n$ 个节点,记 $sum_k$ 为节点 $k$ 的旧边权之和,$d_{k,l}$ 为节点 $k$ 与结点 $l$ 之间的边权,则 $sum_k-sum_1=(n-3)(d_{k,n}-d_{1,n})$。 至于 $d_{1,n}$ 的取值,直接设为 $d_{n-2,n-1}+1$ 就能避免重复。 # 优化 然而,这种做法在 $n=20$ 时边权最大能达到一万多,远超题目限制。 观察到,$n$ 很大时边权跨度非常大,特别浪费。 因为数据范围很小,我们可以不直接将 $d_{1,n}$ 设为 $d_{n-2,n-1}+1$,而是暴力遍历 $1\sim1000$,找出 $d_{1,n}$ 合法的最小取值。 # 代码 ```cpp #include<bits/stdc++.h> using namespace std; #define int long long int n,w[25],d[25][25],fl,f[1005]; signed main(){ cin>>n; d[1][2]=d[2][1]=1; d[1][3]=d[3][1]=2; d[3][2]=d[2][3]=3; f[1]=f[2]=f[3]=1; w[1]=3; w[2]=4; w[3]=5; for(int i=4;i<=n;i++){ for(int j=1;j<=1000;j++){ fl=1; for(int k=1;k<i;k++){ d[i][k]=d[k][i]=(w[k]-w[1])/(i-3)+j; if(f[d[i][k]]){ fl=0; break; } } if(fl)break; } for(int j=1;j<i;j++){ w[j]+=d[i][j]; w[i]+=d[i][j]; f[d[i][j]]=1; } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++)cout<<d[i][j]<<" "; cout<<"\n"; } } ``` 时间复杂度为 $O(n^2V)$,空间复杂度为 $O(\max\{n^2,V\})$。