B. Fridge Lockers

原题链接

tags: graphs、implementation

思路:
铁 链 数 n < 冰 箱 数 m 铁链数n<冰箱数m n<m时,由于每一个冰箱都需要被两条锁链锁住,所以必然有 铁 链 数 n > = 冰 箱 数 m 铁链数n>=冰箱数m n>=m,此时必然不可行,直接输出-1。
铁 链 数 n = = 冰 箱 数 m 铁链数n==冰箱数m n==m时,每一个点的花费 a i a_i ai都会被使用两次,所以总花费为 s u m = 2 ∗ ∑ i = 1 n a i sum=2*\sum_{i=1}^{n} a_{i} sum=2i=1nai 。为了避免输出过于复杂而且每个点都会被选中两次,我们可以使用一个环来表示他们之间的连接关系,并通过循环可以将其依次输出。
进一步当 铁 链 数 n > 冰 箱 数 m 铁链数n>冰箱数m n>m时,为了使总的花费最小,我们必然会选择两个最小的点来承受这些铁链,此时得到的最小总花费为 s u m = 2 ∗ ∑ i = 1 n a i + ( n − m ) ∗ ( m i n 1 + m i n 2 ) sum=2*\sum_{i=1}^{n} a_{i}+(n-m)*(min _1+min_2) sum=2i=1nai+(nm)(min1+min2)。由于当 m = = n m==n m==n时, n − m = 0 n-m=0 nm=0。所以当 n > = m n>=m n>=m时,该公式都适用。

另外,当 n = = 2 n==2 n==2时,该样例必然不可行,这点很容易遗漏。
代码如下:

//#include<bits/stdc++.h>
#include<cmath>
#include<stack>
#include<cstdio>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<iostream>
#include<string>
#include<sstream>
#include<algorithm>
#include<string.h>
#include<stdlib.h> 
typedef long long ll;
using namespace std;
inline int read() {
	int s = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}
const int maxn=1e3;
int a[maxn+5];
int main()
{
	int T;
	cin>>T;
	while(T--){
		int n,m,sum=0;
		int min_num1=1e4+5,min_num2=1e4+5,min_add1,min_add2;
		cin>>n>>m;
		for(int i=0;i<n;i++){
			scanf("%d",&a[i]);
			//求基础的sun和
			sum+=a[i];
			//求得序列中最小两个元素的值及其位置
			if(a[i]<min_num1){
				min_num2=min_num1;min_add2=min_add1;
				min_num1=a[i];min_add1=i+1;
			}
			else if(a[i]<min_num2){
				min_num2=a[i];min_add2=i+1;
			}
		}
		if(m<n||n==2) printf("-1\n");
		else{
			printf("%d\n",2*sum+(m-n)*(min_num1+min_num2));
			//将锁链以环状连接所有的点
			for(int i=1;i<=n;i++){
				if(i<n) printf("%d %d\n",i,i+1);
				else printf("%d %d\n",i,1);
			}
			//多余的锁链都拿去连接最小的两个点
			for(int i=n+1;i<=m;i++){
				printf("%d %d\n",min_add1,min_add2);
			}
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rockict_z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值