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=2∗∑i=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=2∗∑i=1nai+(n−m)∗(min1+min2)。由于当
m
=
=
n
m==n
m==n时,
n
−
m
=
0
n-m=0
n−m=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;
}