1. 程式人生 > >BNU 51645 ACM Battle【思維+爆搜】確實挺隱祕的一個爆搜題

BNU 51645 ACM Battle【思維+爆搜】確實挺隱祕的一個爆搜題

ACM Battle

Time Limit: 2000ms Memory Limit: 262144KB 64-bit integer IO format: %lld      Java class name: Main Type:  None  

古往今來的各種傳說中存在著很多魔法陣,它們的啟用方式也各不相同。傳說在北師大電子樓前的小花園裡就有一個魔法陣,上次出現還是在很多很多很多年前,但是現在它又出現了!

這時,小Q同學面無表情地說:“傳說這個魔法陣都會在都會在來自遠古的惡魔Awesome Crystal Monster(ACM)降臨的時候出現,現在,這個時候終於要到來了嗎!”話音未落,小Q同學已經走到了魔法陣前,取出一個小瓶,開始用瓶中的聖水啟用這個魔法陣,“你們快退後,這裡就交給我了!”

這個魔法陣由一些點和一些連線這些點的邊構成,當小Q同學把聖水滴在一個點上時,和這個點相連的所有邊就會被點亮併發出神聖的光芒,當魔法陣所有的邊都點亮的時候,就會出現強大的神聖力量。但是小Q同學擁有的聖水非常有限,只有10滴,現在小Q同學想知道他最少可以用多少滴聖水點亮整個魔法陣,如果耗盡聖水也不能點亮,就只能打出一波GG了。

Input

第一行包含一個正整數T(\leq 20),表示測試資料的組數,

對於每組測試資料,

第一行是兩個整數n(1 \leq n \leq 1000)m(1 \leq m \leq 2000),表示魔法陣的點數和邊數,

接下來m行,每行包含兩個整數u,v(1 \leq u,v \leq n),表示有一條邊連線了u號點和v號點。

Output

對於每組測試資料,如果使用不超過10滴聖水可以點亮整個魔法陣,輸出最少需要的聖水滴數,否則輸出"GG"(不含引號)。

Sample Input

2
4 3
1 2
1 3
1 4
4 4
1 2
2 3
3 4
4 1

Sample Output

1
2

Hint

對於第一組樣例,最優方案是在1號點滴一滴聖水,

對於第二組樣例,一個最優方案是在1號點和3號點各滴一滴聖水。

Source

Author

Mashiro

思路:

一開始讀完題下意識的就覺得是最小點覆蓋問題,然而忘記這個圖可能會存在(奇數長度)環的問題了,直接閉著眼睛去搞了一發。

然後發現不能處理變成二分圖。

當然也不能樹型Dp去求最小點覆蓋數。

問題焦點肯定鎖定在10個點上來。

所以我們著重考慮10個點的問題。

對於這十個點的列舉我想了半天,後來才發現不妨去列舉邊。(這題的爆搜思路還是挺隱祕的,反正窩不太常見這種題,我不太能一眼看出來,要思考好久好久啊-----);

鍛鍊了這樣的能力,蠻開心。

我們要染到所有的邊,所以我們不妨去列舉邊,對於一條邊來講:

①如果其之前選的點之中選擇過了這條邊的某個點,那麼這條邊就已經被染上了不用去管。

②如果這條邊沒有被染過,那麼對應有兩種選擇,要麼去染u,要麼去染v.如果就單單這一條邊我們就要將兩個點都處理了的話是沒有必要的,所以我們這裡列舉一種情況即可。

那麼對於每一條邊我們都去列舉情況的話,時間複雜度可是要達到O(2^m)的啊;

看起來是這樣的,迴歸焦點,我們一旦已經列舉過了10個點出來,而當前邊還需要選擇一個點去選擇,那麼當前情況就可以剪枝掉。

所以最壞的時間複雜度其實是O(2^10*m);

那麼我們爆搜處理維護最小值即可

Ac程式碼:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
struct node
{
    int x,y;
}a[2500];
int n,m;
int ans;
int vis[2500];
void Dfs(int u,int sum)
{
    if(sum>10)return ;
    if(u==m)
    {
        ans=min(ans,sum);
        return ;
    }
    if(vis[a[u].x]==1||vis[a[u].y]==1)Dfs(u+1,sum);
    else
    {
        vis[a[u].x]=1;
        Dfs(u+1,sum+1);
        vis[a[u].x]=0;
        vis[a[u].y]=1;
        Dfs(u+1,sum+1);
        vis[a[u].y]=0;
    }
    return ;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)scanf("%d%d",&a[i].x,&a[i].y);
        ans=0x3f3f3f3f;
        Dfs(0,0);
        if(ans<=10)
        printf("%d\n",ans);
        else printf("GG\n");
    }
}