5 2

本文探讨了最小生成树算法在公路网建设中的应用,通过排序和并查集实现最优路径选择,以及使用二分查找法快速确定一组数字中所有两两差值的中位数,介绍了算法的具体实现和优化技巧。

最小生成树——公交网建设

有一张城市地图,图中的顶点为城市,无向边代表两个城市间的连通关系,边上的权为在这两个城市之间修建高速公路的造价,研究后发现,这个地图有一个特点,即任一对城市都是连通的。现在的问题是,要修建若干高速公路把所有城市联系起来,问如何设计可使得工程的总造价最少?

【输入】
n(城市数,1<≤n≤100)

e(边数)

以下e行,每行3个数i,j,wij,表示在城市i,j之间修建高速公路的造价。

【输出】
n-1行,每行为两个城市的序号,表明这两个城市间建一条高速公路。

【输入样例】
​5 8
1 2 2
2 5 9
5 4 7
4 1 10
1 3 12
4 3 6
5 3 3
2 3 8

【输出样例】
1  2
2  3
3  4
3  5
 

这题刚开始想着比较难,不过也就是前面学的几个东西的结合。第一个问题就是怎么让这几个城市都连起来,然后就是让总的路程最短。

都连起来就可以用family的函数让n个城市全都连起来。总的路程最短就很简单了。让m个路先进行排序,然后在进行全连起来的操作,这样找到的n-1个路就一定是最短的了。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define inf 0x3f3f3f3f
int n,m,f[110];
struct Node 
{
	int u,v,w;
}e[10010],ans[110]; 
                      
bool cmp1(Node a,Node b)
{
	return a.w<b.w;
}

bool cmp2(Node a,Node b)
{
	if (a.u!=b.u) return a.u<b.u;         
	else return a.v<b.v;                   
}

int f (int x)
{
	if (x==f[x]) return x;
    else 
    {
	    f[x]=find(f[x]);
	    return f[x];
	}
	
}
int family(int u,int v)
{
	int t1=f(u);
	int t2=f(v);
    if (t1!=t2) 
	{
		f[t2]=t1;
		return 1;
	}
	return 0;
}
int main ()
{
	int count=0,k=0;
	cin>>n>>m;
	for (int i=1;i<=m;i++)
		cin>>e[i].u>>e[i].v>>e[i].w;
	sort(e+1,e+m+1,cmp1);
	for (int i=1;i<=n;i++)
	    f[i]=i;
	
	for (int i=1;i<=m;i++)
	{
		if (family(e[i].u,e[i].v))
		{
			k++;
			if (e[i].u<e[i].v) ans[k].u=e[i].u,ans[k].v=e[i].v;
			else ans[k].u=e[i].v,ans[k].v=e[i].u;
		}                            
		if (count==n-1) 
			break;
	}

	sort(ans+1,ans+k+1,cmp2);
	for (int i=1;i<=k;i++)
	    cout<<ans[i].u<<" "<<ans[i].v<<endl;
	return 0;
}

 

二分——F

Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numbers: ∣Xi -Xj∣ (1 ≤ i  j  N). We can get C(N,2) differences through this work, and now your task is to find the median of the differences as quickly as you can!

Note in this problem, the median is defined as the (m/2)-th  smallest number if m,the amount of the differences, is even. For example, you have to find the third smallest one in the case of = 6.

Input

The input consists of several test cases.
In each test case, N will be given in the first line. Then N numbers are given, representing X1, X2, ... , XN, ( Xi ≤ 1,000,000,000  3 ≤ N ≤ 1,00,000 )

Output

For each test case, output the median in a separate line.

Sample Input

4
1 3 2 4
3
1 10 2

Sample Output

1
8

这题题意很简单,就是给n个数,这n个数中所有数对的差中排序最中间的数。题意简单思路也简单,只是不知道怎么去优化,如果要用二分法的话,找最中间的数,left是1 right就是最大的差,关键是怎么找,就是先找到一个数x,最好找的方法就是先给n个数排序,然后把每个数拿出来,找到每个数相差x的数,这样最后得到的和就是相差x之内的数对数,这样二分查找最后就可以找到了。

这里还学了俩函数感觉挺好用的。

lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int a[100002];
int i,j,n,k;
bool check(int x){
	int cnt=0;
	for(i=0;i<n;i++)
	{
		int t=upper_bound(a,a+n,a[i]+x)-a;
		cnt+=(t-i-1);
	}
	if(cnt>=k)
		return true;
	    return false;
}
int main()
{
	
    int mid,m;

	while(cin>>n)
	{
         for(i=0;i<n;i++)
			 cin>>a[i];

		sort(a,a+n);

        m=n*(n-1)/2;
		k=(m+1)/2;

		int l=1,r=a[n-1]-a[0];
		int ans;

		while(l<=r)
		{
			mid=(l+r)>>1;
			if(check(mid))
			{
				ans=mid;
				r=mid-1;
			}
			else
				l=mid+1;
		}
		cout<<ans<<endl;
	}
	return 0;

   
}


暂时只能想到这些,感觉二分法形式比较固定,挺简单的,(也可能是我没还见到难题)。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值