地震之后
总时间限制:1000ms内存限制:130000kB描述
对于每一组测试数据:
1、第一行包括两个整数N(1<=N<=100),M(M<<=10000),N表示通信网络中村子的数量,M表示在这些村子中,可以有M条通信线路建起来。
2、接下来N行,每行两个整数xi,yi,代表着这个村子的X轴,Y轴的坐标(xi,yi)
3、接下来M行,每行两个整数c1(1<=c1<=N),c2(1<=c2<=N),代表着从村c1到村c2可以建一个单向线路。
注:两村之间的直线段距离(通信线路长度),即为两点间的欧式距离。
县总部所在的村假设都在编号为1的村。
输入以文件终止为结束。输出对于每一组的测试数据,输出完全的一行,值为最短的总长度,结果保留两位小数。
如果不能建立一个单向的临时网络,输出"NO".样例输入
2008年地震之后,坚强县受灾严重,该县通信线路也收到了致命的打击,县总部为了能够及时的向各村的发送消息,命令小强去解决一下这个问题。
小 强经过调查发现,为了能够快速的实现通信,当务之急是能够建立起一条从总部可以向各个村单向发送信息的通信系统。由于灾后情况紧急,不是每一个村之间都能 够快速的建立起通信线路,只有有限的村比如村A和村B间可以建立单向的从A向B发送信息的通信线路,小强现在的问题就是要找出一个合适的方案,使从总部发 送出的信息能够通到各村,而用的总的通信线路是最短的(毕竟情况危急,物质短缺)。
输入输入包括多组的测试数据。对于每一组测试数据:
1、第一行包括两个整数N(1<=N<=100),M(M<<=10000),N表示通信网络中村子的数量,M表示在这些村子中,可以有M条通信线路建起来。
2、接下来N行,每行两个整数xi,yi,代表着这个村子的X轴,Y轴的坐标(xi,yi)
3、接下来M行,每行两个整数c1(1<=c1<=N),c2(1<=c2<=N),代表着从村c1到村c2可以建一个单向线路。
注:两村之间的直线段距离(通信线路长度),即为两点间的欧式距离。
县总部所在的村假设都在编号为1的村。
输入以文件终止为结束。输出对于每一组的测试数据,输出完全的一行,值为最短的总长度,结果保留两位小数。
如果不能建立一个单向的临时网络,输出"NO".样例输入
4 6
3 6
4 6
3 4
7 20
1 2
1 3
2 3
3 4
3 1
3 2
4 3
0 0
1 0
1 1
1 2
1 3
4 1
2 3
样例输出
19.49
NO
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#define MAXN 120
#define inf 1000000000
double len[MAXN * 2][MAXN * 2] = {0};
class poi
{
public:
int x;
int y;
};
poi po[MAXN];
typedef double elem_t;
//以下为模板
//多源最小树形图,edmonds算法,邻接阵形式,复杂度O(n^3)
//返回最小生成树的长度,构造失败返回负值
//传入图的大小n和邻接阵mat,不相邻点边权inf
//可更改边权的类型,pre[]返回树的构造,用父结点表示
//传入时pre[]数组清零,用-1标出源点
elem_t edmonds (int n, elem_t mat[][MAXN * 2], int *pre)
{
elem_t ret = 0;
int c[MAXN * 2][MAXN * 2], l[MAXN * 2], p[MAXN * 2], m = n, t, i, j, k;
for (i = 0; i < n; l[i] = i, i++);
do
{
memset (c, 0, sizeof (c)), memset (p, 0xff, sizeof (p));
for (t = m, i = 0; i < m; c[i][i] = 1, i++);
for (i = 0; i < t; i++)
if (l[i] == i && pre[i] != -1)
{
for (j = 0; j < m; j++)
if (l[j] == j && i != j && mat[j][i] < inf
&& (p[i] == -1 || mat[j][i] < mat[p[i]][i]))
p[i] = j;
if ((pre[i] = p[i]) == -1)
return -1;
if (c[i][p[i]])
{
for (j = 0; j <= m; mat[j][m] = mat[m][j] = inf, j++);
for (k = i; l[k] != m; l[k] = m, k = p[k])
for (j = 0; j < m; j++)
if (l[j] == j)
{
if (mat[j][k] - mat[p[k]][k] < mat[j][m])
mat[j][m] = mat[j][k] - mat[p[k]][k];
if (mat[k][j] < mat[m][j])
mat[m][j] = mat[k][j];
}
c[m][m] = 1, l[m] = m, m++;
}
for (j = 0; j < m; j++)
if (c[i][j])
for (k = p[i]; k != -1 && l[k] == k;
c[k][j] = 1, k = p[k]);
}
}
while (t < m);
for (; m-- > n; pre[k] = pre[m])
for (i = 0; i < m; i++)
if (l[i] == m)
{
for (j = 0; j < m; j++)
if (pre[j] == m && mat[i][j] == mat[m][j])
pre[j] = i;
if (mat[pre[m]][m] == mat[pre[m]][i] - mat[pre[i]][i])
k = i;
}
for (i = 0; i < n; i++)
if (pre[i] != -1)
ret += mat[pre[i]][i];
return ret;
}
int main()
{
int poin = 0, linen = 0;
int par[MAXN] = {0};
while(scanf ("%d%d", &poin, &linen) != EOF)
{
//init
memset(par, 0, sizeof(par));
memset(len, 0, sizeof(len));
par[0] = -1;
for (int i = 0; i < MAXN; ++i)
for (int j = 0; j < MAXN; ++j)
{
if (i == j) len[i][j] = 0;
else len[i][j] = inf;
}
int ix = 0, iy = 0;
for (int i = 0; i < poin; ++i)
{
scanf("%d%d", &ix, &iy);
po[i].x = ix;
po[i].y = iy;
}
int src = 0, dest = 0;
for (int i = 0; i < linen; ++i)
{
scanf("%d%d", &src, &dest);
--src;
--dest;
double dx = po[src].x - po[dest].x;
double dy = po[src].y - po[dest].y;
double length = sqrt(dx*dx + dy*dy);
if (len[src][dest] > length)
{
len[src][dest] = length;
}
}
/*test
for (int i = 0 ; i < poin; ++i)
{
for (int j = 0 ; j < poin; ++j)
printf("%.1lf ", len[i][j]);
printf("\n");
}
*/
double ans = edmonds (poin, len, par);
if (ans >= 0) printf("%.2lf\n", ans);
else printf("NO\n");
}
return 0;
}