二分图即需要将集合分为两部分,每部分的度数之和相等
因此问题转化为:在集合中找到一个子集,使得子集的度数和为全部节点度数和的一半
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); } }