BNU 51645 ACM Battle【思維+爆搜】確實挺隱祕的一個爆搜題
ACM Battle
Time Limit: 2000ms Memory Limit: 262144KB 64-bit integer IO format: %lld Java class name: Main Type:古往今來的各種傳說中存在著很多魔法陣,它們的啟用方式也各不相同。傳說在北師大電子樓前的小花園裡就有一個魔法陣,上次出現還是在很多很多很多年前,但是現在它又出現了!
這時,小Q同學面無表情地說:“傳說這個魔法陣都會在都會在來自遠古的惡魔Awesome Crystal Monster(ACM)降臨的時候出現,現在,這個時候終於要到來了嗎!”話音未落,小Q同學已經走到了魔法陣前,取出一個小瓶,開始用瓶中的聖水啟用這個魔法陣,“你們快退後,這裡就交給我了!”
Input
第一行包含一個正整數,表示測試資料的組數,
對於每組測試資料,
第一行是兩個整數和,表示魔法陣的點數和邊數,
接下來行,每行包含兩個整數,表示有一條邊連線了號點和號點。
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");
}
}