http://acm.hdu.edu.cn/showproblem.php?pid=6090
很简单的一道题,因为自己不够贪心所以还是细节漏了点。
给出n个点m条边,去把n个点连起来,边不够的话也可以连,只不过权值变成了n,正常的边权值等于该2点间的边的数量,求从map[1][1]到map[n][n]的和最小。
因为m条边不一定全用完,那么肯定2个点最多只会连1条边,因为数据特别大,所以肯定是有公式的,既然有公式,那么图就一定很好算,很容易就能想到图是一个从1个点想四周去延展的网状图,那么就很简单了,从中心点到四周都是1,从四周到其他四周点,都是2,这是正好是最小生成树边数的情况,如果边不够,就把多余点连到中心点上,权值为n,如果m>n-1那么多一条边,答案就减2,可以打表发现,也可以自己理解(因为本来相连是2的,现在变成1了,一来一回就减少了2)。
如果m>=(n-1)*n/2那么答案就是一张边全为1的完全图。
重点!因为权值为n的边是可以任意连的,是没有数量限制的,所以如果边不够的话,多余的点不应该是只用权值为n的边连到中心点的,应该是往其余每个点上都连一条权值为n的边。。。这就是为什么我不够贪心的原因,真的是太蠢了我。。。
#include<iostream>
using namespace std;
long long n,m;
int main(){
long long t;
cin>>t;
while(t--)
{
cin>>n>>m;
if(n==1)
{
cout<<"0"<<endl;
continue;
}
if(m>=(n-1)*n/2)
{
long long ans=n*(n-1);
cout<<ans<<endl;
}
else if(m>n-1)
{
long long ans=2*n*(n-1);
ans=ans-2*m;
cout<<ans<<endl;
}
else if(m<=n-1)
{
long long y=n-m-1;
long long ans1=y*n*(n-1)+(n-y)*y*n;
long long ans2=m+m+2*m*(m-1);
long long ans=ans1+ans2;
cout<<ans<<endl;
}
}
return 0;
}