地震之后

6:地震之后

总时间限制: 
1000ms 
内存限制: 
130000kB
描述

  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<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<iomanip>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<set>
    #include<map>
    using namespace std;
    struct Node
    {
    	int  x,y;
    }p[105];
    struct Edge
    {
    	int s,t;
    	double w; 
    }e[10005];
    double Inw[105];
    int vis[105];
    int newid[105];
    int pre[105];
    double Dis(int s,int t)
    {
    	double a=p[s].x-p[t].x;
    	double b=p[s].y-p[t].y;
    	return sqrt(a*a+b*b);
    }
    double DirMST(int root,int n,int m)
    {
    	double ans=0;
    	while(true)
    	{
    		for(int i=0;i<n;++i) Inw[i]=0x7fffffff>>1;
    		for(int i=0;i<m;++i)
    		{
    			int s=e[i].s,t=e[i].t;
    			if(s==t)continue;
    			if(e[i].w<Inw[t])
    			{
    				Inw[t]=e[i].w;
    				pre[t]=s;
    			}
    		}
    		
    		for(int i=0;i<n;++i)
    		{
    			if(i==root)continue;
    			if(Inw[i]==0x7fffffff>>1)return -1;
    		}
    		
    	 	for (int i=0; i<n; ++i)  
            {  
                vis[i]=-1;  
                newid[i]=-1;  
            } 
    		 
    		int num=0;
    		Inw[root]=0;
    		
    		for(int i=0;i<n;++i)
    		{
    			ans+=Inw[i];
    			int v=i;
    			while(vis[v]!=i&&newid[v]==-1&&v!=root)
    			{
    				vis[v]=i;v=pre[v];
    			}
    			
    			if(v!=root&&newid[v]==-1)
    			{
    				for(int u=pre[v];u!=v;u=pre[u])
    				{
    					newid[u]=num;
    				}
    				newid[v]=num;
    				num++;
    			}
    		}
    		
    		if(num==0)return ans;
    		
    		for(int i=0;i<n;++i) 
    		{
    			if(newid[i]==-1) 
    				newid[i]=num++;
    		}
    		
    		for(int i=0;i<m;++i)
    		{
    			int s=e[i].s,t=e[i].t;
    			e[i].s=newid[s];
    			e[i].t=newid[t];
    			if(e[i].s!=e[i].t)
    			{
    				e[i].w-=Inw[t];
    			}
    		}
    		n=num;
    		root=newid[root];
    	}
    }
    int main()
    {
    	int n,m,x,y;
    	
    	while(scanf("%d",&n)!=EOF)
    	{
    		scanf("%d",&m);
    		for(int i=0;i<n;++i)
    		{
    			scanf("%d%d",&p[i].x,&p[i].y);
    		}
    		for(int i=0;i<m;++i)
    		{
    			scanf("%d%d",&e[i].s,&e[i].t);
    			e[i].s--;e[i].t--;
    			e[i].w=Dis(e[i].s,e[i].t);
    		}
    		double ans;
    		ans=DirMST(0,n,m);
    		if(ans==-1)printf("NO\n");
    		else printf("%.2f\n",ans);
    	}
    	return 0;
    }
    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值