hdu6090 Rikka with Graph 2017多校第五场1006 找规律

http://acm.split.hdu.edu.cn/showproblem.php?pid=6090

Rikka with Graph

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 25    Accepted Submission(s): 17


Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

For an undirected graph  G  with  n  nodes and  m  edges, we can define the distance between  (i,j)  ( dist(i,j) ) as the length of the shortest path between  i  and  j . The length of a path is equal to the number of the edges on it. Specially, if there are no path between  i  and  j , we make  dist(i,j)  equal to  n .

Then, we can define the weight of the graph  G  ( wG ) as  ni=1nj=1dist(i,j) .

Now, Yuta has  n  nodes, and he wants to choose no more than  m  pairs of nodes  (i,j)(ij)  and then link edges between each pair. In this way, he can get an undirected graph  G  with  n  nodes and no more than  m  edges.

Yuta wants to know the minimal value of  wG .

It is too difficult for Rikka. Can you help her?  

In the sample, Yuta can choose  (1,2),(1,4),(2,4),(2,3),(3,4) .
 

Input
The first line contains a number  t(1t10) , the number of the testcases. 

For each testcase, the first line contains two numbers  n,m(1n106,1m1012) .
 

Output
For each testcase, print a single line with a single number -- the answer.
 

Sample Input
  
  
1 4 5
 

Sample Output
  
  
14
 

Source
 

题意:有n个点,你可以填上m条边。连通的两点间的距离就是最短路上的边数,不连通的话是n。求出填上边后的距离之和的最小值。

题解:多写几组之后发现,最优的填法是:选定一个点,先把该点与其他所有点连满,若有多的边,再选下一个点与其他点连满(这或许是一个结论,但是图论学的不精)。计算的时候我是用全部不连的状态减去每次连边后两点间的距离减少的值,具体看代码理解。
代码:
#include<bits/stdc++.h>
#define debug cout<<"aaa"<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;

const int N = 100000 + 5;
const int mod = 1000000000 + 7;

int main(){
	int t;
	LL n,m,ans;
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld",&n,&m);
		ans=n*n*(n-1);
		if(m<=n-1){
			//减去减少的距离,这个形成的是一颗树:有m个叶子节点,都连在根节点上,其余的都是孤立点距离不变 
			ans=ans-m*(m-1)*(n-2)-2*m*(n-1);
		}
		else if(m>n*(n-1)/2){
			//全部连上的情况,直接计算结果 
			ans=n*(n-1);
		}
		else{
			//连上n-1条边后就是一颗树:有n-1个叶子节点,都连在根节点上
			//在这棵树上再添加边,那么这条边上的两点的距离就从原来的2,变成了1 
			ans=ans-2*(n-1)*(n-1)-2*(m-n+1)-(n-1)*(n-2)*(n-2);
		}
		printf("%lld\n",ans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值