看這個知識點純屬臨時抱佛腳,畢竟每年PKU時不時會出些圖論的偏知識點,大致瞭解一下思路也好。
用到的是朱劉算法,具體過程網上都有,我就不贅述了。貌似這道題還是我們WHUACM前輩們出的?題幹裏好多熟悉的名字啊。
要注意的是,初始化鄰接矩陣的時候,和最小生成樹一樣,都要賦爲Inf,否則最後求出來的值就成0了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define inf 99999999
const int maxn = 222;
int n, m;
double a[maxn][maxn];
struct node
{
double x, y;
}p[maxn];
double get_dist(node p1, node p2)
{
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
double zhuliu()
{
bool visit[maxn], flag[maxn];
int pre[maxn];
double sm = 0;
int i, j, k;
for(i = 0; i < n; i ++)
{
flag[i] = false;
a[i][i] = inf;
}
pre[0] = 0;
while(true)
{
for(i = 1; i < n; i ++)
{
if(flag[i]) continue;
pre[i] = i;
for(j = 0; j < n; j ++)
if(!flag[j] && a[j][i] < a[pre[i]][i])
pre[i] = j;
if(pre[i] == i)
return -1;
}
for(i = 1; i < n; i ++)
{
if(flag[i]) continue;
for(j = 0; j < n; j ++)
visit[j] = false;
visit[0] = true;
j = i;
do{
visit[j] = true;
j = pre[j];
}while(!visit[j]);
if(!j) continue;
i = j;
do{
sm += a[pre[j]][j];
j = pre[j];
}while(j != i);
j = i;
do{
for(k = 0; k < n; k ++)
if(!flag[k] && a[k][j] < inf && k != pre[j])
a[k][j] -= a[pre[j]][j];
j = pre[j];
}while(j != i);
for(j = 0; j < n; j ++)
{
if(j == i) continue;
for(k = pre[i]; k != i; k = pre[k])
{
if(a[k][j] < a[i][j]) a[i][j] = a[k][j];
if(a[j][k] < a[j][i]) a[j][i] = a[j][k];
}
}
for(j = pre[i]; j != i; j = pre[j])
flag[j] = true;
break;
}
if(i == n)
{
for(i = 1; i < n; i ++)
if(!flag[i])
sm += a[pre[i]][i];
break;
}
}
return sm;
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
for(int i = 0; i < n; i ++)
scanf("%lf%lf", &p[i].x, &p[i].y);
for(int i = 0; i < n; i ++)
for(int j = 0; j < n; j ++)
a[i][j] = inf;
for(int i = 0; i < m; i ++)
{
int u, v;
scanf("%d%d", &u, &v);
u --, v --;
a[u][v] = get_dist(p[u], p[v]);
}
double ans = zhuliu();
if(ans >= 0.0)
printf("%.2lf\n", ans);
else
printf("poor snoopy\n");
}
}