二分图即需要将集合分为两部分,每部分的度数之和相等
因此问题转化为:在集合中找到一个子集,使得子集的度数和为全部节点度数和的一半
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static int halfDegree;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
int nodeNum = in.nextInt();
int[] nodeDegree = new int[nodeNum];
int sumDegree = 0;
for(int i = 0;i < nodeNum;i++){
int degree = in.nextInt();
nodeDegree[i] = degree;
sumDegree += degree;
}
halfDegree = sumDegree/2;
// 当度数和为奇数时失败
if(sumDegree % 2 == 1){
System.out.print(-1);
return;
}
int[] status = new int[nodeNum];
// 寻找度数和为全体度数和一半的子集
int[] result = find(nodeDegree,status,0,0);
if(result[0] == -1){
System.out.print(-1);
return;
}
else System.out.println(halfDegree);
int rightPoint = 0;
for(int leftPoint = 0;leftPoint < nodeNum;leftPoint ++){
if(result[leftPoint] == 0)continue;
else{
while(nodeDegree[leftPoint] != 0){
while(rightPoint != nodeNum){
if(nodeDegree[rightPoint] != 0 && status[rightPoint] == 0)break;
rightPoint++;
}
System.out.println(leftPoint < rightPoint ?(leftPoint + 1) + " " + (rightPoint + 1) : (rightPoint + 1) + " " + (leftPoint + 1));
nodeDegree[leftPoint] --;
nodeDegree[rightPoint] --;
}
}
}
}
public static int[] find(int[] nodeDegree,int[] status,int curDegree,int curPos){
if(curPos == nodeDegree.length){
//如果没有可行的分配方式,标记首位为-1
status[0] = -1;
return status;
}
if(curDegree == halfDegree) return status;
if(curDegree + nodeDegree[curPos] == halfDegree){
status[curPos] = 1;
return status;
}
if(curDegree + nodeDegree[curPos] < halfDegree){
status[curPos] = 1;
int[] newStatus = find(nodeDegree,status,curDegree + nodeDegree[curPos],curPos + 1);
if(newStatus[0] != -1) return newStatus;
status[curPos] = 0;
}
return find(nodeDegree,status,curDegree,curPos + 1);
}
}



京公网安备 11010502036488号