最大團問題
阿新 • • 發佈:2018-12-24
簡單的講最大團就是最大完全子圖
給了一個最多包含 50 個點的無向圖,讓求這個圖中最大團所包含的的點的數量
直接套模板就行。。
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
struct node{
static const int N = 60; //可修改
bool G[N][N]; //初始化
int n, Max[N], Alt[N][N], ans;
bool dfs(int cur, int tol){
if(cur == 0){
if(tol>ans){ // 用一個更大的極大團替代原有的極大團
ans = tol;
return 1;
}
return 0;
}
for (int i=0; i<cur; i++){
if(cur-i+tol <= ans)return 0;
int u = Alt[tol][i];
if(Max[u]+tol <= ans)return 0;
int nxt = 0;
for(int j=i+1; j<cur; j++)
if(G[u][Alt[tol][j]])Alt[tol+1][nxt++] = Alt[tol][j];
if(dfs(nxt, tol+1)) return 1;
}
return 0;
}
int max_clique(){
ans = 0;
mst(Max, 0);
for(int i=n-1; i>=0; i--){ // 先找一個點,把與它相連的點加進來,這些點可能構成最大團,然後dfs判斷出一個臨時極大團
int cur = 0;
for(int j=i+1; j<n; j++)if(G[i][j])Alt[1][cur++] = j;
dfs(cur, 1);
Max[i] = ans;
}
return ans;
}
};
node mc;
int main(){
while(~scanf("%d", &mc.n)){
if(!mc.n)break;
for(int i=0; i<mc.n; i++)
for(int j=0; j<mc.n; j++)
scanf("%d", &mc.G[i][j]); //G[u][v]表示u,v之間是否有邊
printf("%d\n", mc.max_clique());
}
return 0;
}
給了一個有 n 個點 m 條邊的無向圖,要求用黑、白兩種色給圖中頂點塗色,相鄰的兩個頂點不能塗成黑色,求最多能有多少頂點塗成黑色。圖中最多有 100 個點
從相鄰的點不能夠塗上相同的顏色我們可以得出該題的實質就是要求一個最大的點獨立集,而求一個圖的點獨立集如果所給的圖是一棵樹的話,就可以通過拆點轉化為二分圖來解了,由於給定的圖很可能成環,因此化作二分圖的做法在這裡不再適應。另一個對應的問題就是通過對原圖建一個反圖,然後對反圖做一個最大團的求解,最大團保證了是反圖中的最大完全子集,任何兩個元素之間都有邊相連,反應在原圖中則是任意兩兩之間不存在邊,也就是兩兩不相鄰,這剛好契合的題意。
ps:這題需要記錄頂點
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
// **** 表示記錄頂點的部分
struct node{
static const int N = 105; //可修改
bool G[N][N]; // 點標號從0開始 Ķ
int n, Max[N], Alt[N][N], ans;
int tmp[N], ret[N]; // ****
bool dfs(int cur, int tol){
if(cur == 0){
if(tol>ans){
memcpy(ret, tmp, sizeof tmp); // **** 用一個更大的極大團替代原有的極大團
ans = tol;
return 1;
}
return 0;
}
for(int i=0; i<cur; i++){
if(cur-i+tol <= ans)return 0;
int u = Alt[tol][i];
if(Max[u]+tol <= ans)return 0;
int nxt = 0;
for(int j=i+1; j<cur; j++)
if(G[u][Alt[tol][j]])Alt[tol+1][nxt++] = Alt[tol][j];
tmp[tol+1] = u;// ****
if(dfs(nxt, tol+1)) return 1;
}
return 0;
}
int max_clique(){
ans = 0;
mst(Max, 0);
for(int i=n-1; i>=0; i--){
int cur = 0;
tmp[1] = i;// ****
for(int j=i+1; j<n; j++)if(G[i][j])Alt[1][cur++] = j;
dfs(cur, 1);
Max[i] = ans;
}
return ans;
}
};
node mc;
int main(){
int T, m;
scanf("%d", &T);
while(T--){
mst(mc.G, true);
scanf("%d%d", &mc.n, &m);
for(int i=1; i<=m; i++){
int u, v;
scanf("%d%d", &u, &v);
mc.G[u-1][v-1] = mc.G[v-1][u-1] = 0;
}
int ans = mc.max_clique();
printf("%d\n", ans);
for(int i=1; i<=ans; i++){
printf("%d%c", mc.ret[i]+1, i==ans?'\n':' '); //注意輸出標號是否+1
}
}
return 0;
}
最多 26 廣播電臺…我還是講抽象之後的題意吧:最多26個點的無向圖,要求相鄰的節點不能染成同一個顏色,問最少需要多少顏色染完所有的頂點
利用上面提到的結論:圖的染色問題中,最少需要的顏色的數量=最大團點的數量,建圖,跑最大團即可
直接爆搜,理論複雜度是O(n*n*m)
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 25;
int n, m;
bool mp[N][N], fg;
int col[N];
void dfs(int x, int tol){//當前點 最大色彩數
if(fg)return ;
if(x == n+1){
fg = 1;
return ;
}
for(int i=1; i<=min(x, tol); i++){
col[x] = i;
bool ok = 1;
for(int j=1; j<x; j++){
if(mp[x][j] && col[x] == col[j]){
ok = 0;
break;
}
}
if(ok)dfs(x+1, tol);
}
}
char s[30];
int main(){
while(~scanf("%d", &n), n){
mst(mp, 0);
for(int i=1; i<=n; i++){
scanf("%s", s);
for(int j=2; s[j]; j++)
mp[s[0]-'A'+1][s[j]-'A'+1] = 1;
}
fg = 0;
for(int i=1; i<=n; i++){
dfs(1, i);
if(fg){
if(i == 1)printf ("1 channel needed.\n");
else printf ("%d channels needed.\n", i);
break;
}
}
}
return 0;
}
以下程式碼作廢:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
struct node{
static const int N = 27;
bool G[N][N];
int n, Max[N], Alt[N][N], ans;
bool dfs(int cur, int tol){
if(cur == 0){
if(tol>ans){
ans = tol;
return 1;
}
return 0;
}
for(int i=0; i<cur; i++){
if(cur-i+tol <= ans)return 0;
int u = Alt[tol][i];
if(Max[u]+tol <= ans)return 0;
int nxt = 0;
for(int j=i+1; j<cur; j++)
if(G[u][Alt[tol][j]])Alt[tol+1][nxt++] = Alt[tol][j];
if(dfs(nxt, tol+1)) return 1;
}
return 0;
}
int max_clique(){
ans = 0;
mst(Max, 0);
for(int i=n-1; i>=0; i--){
int cur = 0;
for(int j=i+1; j<n; j++)if(G[i][j])Alt[1][cur++] = j;
dfs(cur, 1);
Max[i] = ans;
}
return ans;
}
};
node mc;
int main(){
while(~scanf("%d", &mc.n), mc.n){
char s[30];
mst(mc.G, 0);
for(int i=1; i<=mc.n; i++){
scanf("%s", s);
for(int j=2; s[j]; j++){
int u = s[0] - 'A', v = s[j] - 'A';
mc.G[u][v] = 1;
}
}
int ans = mc.max_clique();
if(ans == 1)printf("%d channel needed.\n", ans);
else printf("%d channels needed.\n", ans);
}
return 0;
}