1. 程式人生 > >回溯法--最大團(部隊護衛隊問題)

回溯法--最大團(部隊護衛隊問題)

package com.duoduo.day316;
/**
 * 回溯法--最大團問題
 * 問題描述:為組織一支隊伍,希望選出最多的居民加入隊伍中,並保證其中任意兩人均不是仇敵,給定仇敵關係圖,計算構建護衛隊的最佳方案。
 * 問題轉化: 從無向圖G=(V,E),頂點集由n個節點組成的集合{1,2,...n},
 *           選擇一部分節點集V',即節點集合的一個子集,此子集中任意兩點均有邊相連
 *           且包含節點個數是節點集合中所有同類子集中節點數目最多的。
 *           
 * 演算法設計: 1 定義問題的解空間 {x1,x2,x3...xn}  xi=0/1
 *          2 解空間是組織結構: 一棵子集樹
 *          3 搜尋解空間: 約束條件-->判斷是否將第t個節點放入團中(只要第t個節點和前t-1個節點中被選中的節點均有邊相連,則x[t]=1)
 *                       限界條件-->cn+fn>bestn(當前已放入團中節點個數+之後可能的所有剩餘節點個數<=當前最優解包含的節點個數)
 *          4 搜尋空間( 深度優先搜尋-->約束條件(左)-->限界條件(右)   還有t>n 需要回溯   以及t>n 就記錄此時的可行解 return           
 * @author 多多
 *
 */

import java.util.Scanner;
public class Test5_3 {
	public static int N=100;          //預設定義陣列大小
	static int[][] a=new int[N][N];   //圖用鄰接矩陣表示
	static int [] x=new int[N];       //是否將第i個節點加入團中
	static int [] bestx=new int[N];   //記錄最優解
	static int bestn;                 //記錄最優值
	static int cn;                    //當前已放入團中的節點數量
	static int n,m;                   //n為圖中節點數  m為圖中邊數
	
	public static void main(String [] args) {
		Scanner sc=new Scanner(System.in);
		System.out.println("請輸入部落的人數n(節點數):");
		n=sc.nextInt();
		System.out.println("請輸入人與人的友好關係(邊數):");
		m=sc.nextInt();
		System.out.println("請依次輸入有友好關係的兩個人(有邊相連的兩個節點u,v)用空格分開:");
		int u,v;                      //有邊相連的兩個節點u,v
		for(int i=1;i<=m;i++) {
			u=sc.nextInt();
			v=sc.nextInt();
			a[u][v]=a[v][u]=1;        //邊數為1
		}
		
		
		bestn=0;                     //初始最優值為0
		cn=0;                        //初始的團中節點也為0
		backTrack(1);                //從第一個節點進行深度搜索
		System.out.println("國王護衛隊的最大人數為:"+bestn);
		System.out.println("國王護衛隊的成員:");
		for(int i=0;i<=n;i++) {
			if(bestx[i]==1)          //列印最優解中記錄為1的節點標號
				System.out.print(i+" ");
		}
	}

	/*進行深度搜索*/
	private static void backTrack(int t) { //t:當前擴充套件節點在第t層
		if(t>n) {    //達到根節點  記錄可行解 並記錄此時節點數目
			for(int i=1;i<=n;i++) 
				bestx[i]=x[i]; 
			bestn=cn;
			return;
		}
		
		if(place(t)) {       //判斷是否滿足約束條件(邊是否連通)-->左子樹-->把節點加入團中
			x[t]=1;          //左子樹 標記為1
			cn++;            //當前節點數+1
			                  
			backTrack(t+1);  //繼續搜尋t+1層
			cn--;            //回溯   加多少就減多少   回退
		}
		
		if(cn+ n-t> bestn) {  //滿足限界條件  -->右子數
			x[t]=0;
			backTrack(t+1);  
		}
		
		
	}

	private static boolean place(int t) {  //判斷是否可以把節點t加入團中
		boolean ok=true;
		for(int j=1;j<t;j++) {
			if(x[j]==1&& a[t][j]==0) {
				ok=false;
				break;
			}
		}
		
		return ok;
		
	}
}


時間複雜度:

約束O(n)  限界O(1)  總:O(n*2n+1*2n)=O(n*2的n次方)   n為指數

空間複雜度:

輔助陣列 bestp[]  O(n) 從開始節點起最長的路徑為n 

演算法優化:

考慮約束函式O(n) 是否可以改進?

相關推薦

回溯--部隊護衛隊問題

package com.duoduo.day316; /** * 回溯法--最大團問題 * 問題描述:為組織一支隊伍,希望選出最多的居民加入隊伍中,並保證其中任意兩人均不是仇敵,給定仇敵關係圖,計算構建護衛隊的最佳方案。 * 問題轉化: 從無向圖G=(V,E),頂點集由

演算法設計例題:回溯、分枝限界

Description 給定無向圖G=(V,E)。如果UV,且對任意u, v ∈ U 有 (u,v) ∈ E,則稱U是G的完全子圖。G的完全子圖U是G的團,當且僅當U不包含在G的更大的完全子圖中。G的最大團是指G中所含頂點數最多的團。 Input

[51NOD1524] 可除圖的組合,dp

鏈接 ble spa 組合 sin ons .html color 出現的次數 題目鏈接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1524 題意:略。 這個題相當於是找出現最長的整除鏈。

【劍指offer】59、隊列的不熟

最大值 ber 元素 const 所有 刪除元素 windows 窗口 push_back 題目一 給定一個數組和滑動窗口的大小,請找出所有滑動窗口裏的最大值。例如,{2,3,4,2,6,2,5,1}以及窗口大小3,那麽存在6個滑動窗口,最大值分別為{4,4,6,6,6,5

m段的動態規劃

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now y

【洛谷 P3381】小費用SPFA+EK

在最大流的基礎上把BFS換成SPFA即可。 #include<bits/stdc++.h> using namespace std; const int maxn = 100050; const int INF = 0x3f3f3f3f; int head[maxn]; bo

CCF——波動2016-9

問題描述   小明正在利用股票的波動程度來研究股票。小明拿到了一隻股票每天收盤時的價格,他想知道,這隻股票連續幾天的最大波動值是多少,即在這幾天中某天收盤價格與前一天收盤價格之差的絕對值最大是多少。

ZZULIOJ 1176: 查詢字串指標專題

題目描述從鍵盤上輸入多個字串(每個串不超過5個字元且沒有空格),用”*****”作為串輸入結束的標記。從所輸入的若干字串中,找出一個最大的串,並輸出該串。要求最大串的查詢通過呼叫編寫的函式實現 void find(char *name[], int n, int *p) { //

劍指offer——連續子陣列的42題

題目:輸入一個整型陣列,數組裡有正數也有負數。陣列中的一個或連續多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)。 此題同時也是leetcode的原題。此處用兩種方法解答。方法一,叫不出名字,但只需一次遍歷,看程式碼很好理解。方法二,利用動態規劃,

網路流之Dinic演算法

程式碼對應於 POJ - 3281 #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define fuck

小費用講解+模板

         問題引入:最小費用最大流問題是經濟學和管理學中的一類典型問題。在一個網路中每段路徑都有“容量”和“費用”兩個限制的條件下,此類問題的研究試圖尋找出:流量從A到B,如何選擇路徑、分配經過路徑的流量,可以在流量最大的前提下,達到所用的費用最小的要求。如n輛

KM演算法求帶權二分圖的匹配完備匹配

1.基礎知識普及 二分圖的概念 二分圖又稱作二部圖,是圖論中的一種特殊 模型。 設G=(V,{R})是一個無向圖。如頂點集V可分 割為兩個互不相交的子集,並且圖中每條邊 依附的兩個頂點都分屬兩個不同的子集。則圖G成為二分圖。 通俗來講,二分圖指的是這樣一種

小費用拆邊

題目大概意思是,有N個城市M條邊,要從1城市到N城市運送K的物品,求最少花費,每個邊有一個係數ai花費的錢是ai*這條邊上運送物資數的平方,比如在係數為3的邊上運送了2的物品,則需要3*2*2的花費; 思路:由於每條邊的容量不超過5,所以可以把每一條邊拆成容量

網路流小割記錄路徑【POJ1815】

  【POJ1815】 出處:原帖 題意:就是求s點到t點,最少去掉幾個點使得他們不連通。如果無解輸出NO ANSWER!    解題思路 因為最小割只能求割掉幾條邊的解,我們要求的是割掉幾個點。那麼我們可以這樣考慮:把每個點拆成入點和出點。入點->出點權值為1。那麼

uoj#79. 一般圖匹配帶花樹

傳送門 帶花樹 不加證明的說一下過程好了:每次從一個未匹配點\(S\)出發bfs,設\(S\)為\(1\)類點,如果當前點\(v\)在本次bfs中未經過,分為以下兩種情況 1.\(v\)是未匹配點,那麼從\(S\)到\(v\)的路徑就是一條增廣路,把這條路徑增廣即可 2.\(v\)是匹配點,那麼把\(

7-5 交換小值和15 分

7-5 交換最小值和最大值(15 分) 本題要求編寫程式,先將輸入的一系列整數中的最小值與第一個數交換,然後將最大值與最後一個數交換,最後輸出交換後的序列。 注意:題目保證最大和最小值都是唯一

分治法找C語言

根據分治思路找最大值: #include <stdio.h> int max(int a,int b){ if (a >= b) return a; else return b; } int find_max(int i,int j,int num[]){ int

6-5 求自定型別元素的10 分

6-5 求自定型別元素的最大值(10 分)本題要求實現一個函式,求N個集合元素S[]中的最大值,其中集合元素的型別為自定義的ElementType。函式介面定義:ElementType Max( ElementType S[], int N ); 其中給定集合元素存放在陣列S

回溯解決2n皇后8皇后問題

8皇后問題是演算法入門的經典,在8*8的國際象棋上擺放八個皇后,使其不能相互攻擊,即任意兩個皇后都不能處於同一 今天要說的2n皇后問題與傳統的8皇后問題有些不同,在一個n*n的棋盤中,有些位置不允許放皇后,現在要向棋盤中 放入n個黑皇后和n個白皇后,使任意的兩個黑白皇后

求n個數中兩數異或的字母樹

#include <stdio.h> #include <string.h> #include <math.h> #include <iostream> #include <string> #include <