標籤:style blog http io ar color os sp for
題目大意:
有n個城市(n<=35),其中某些城市有邊相連。如果在某一點放一個發電站,與他直接相鄰的城市就可以得到供電。
雖然題目說的是有向圖,但是實際上處理的時候是無向圖。這是根據範例分析出來的。
換種理解就是求一幅無向圖的最小支配集。也就是在圖中找到點數最少的一個點集,使得其他所有的點都和點集中點(一個或多個)有邊相連。
參考部落格:http://blog.csdn.net/hackerwin7/article/details/16344839
題目分析:
NP問題,但資料量小,只有35個頂點,所以可以暴力枚舉。也就是每一頂點有選和不選兩種可能,最後應該有235種可能。這肯定會逾時,所以需要剪枝。
剪枝的情況是:
1、當前的發電站個數大於當前所需最少的發電站個數。這樣已經沒必要進行下去了,因為不可能產生更優的解。
2、如果在某一點放發電站以後,通電的城市的個數沒有增加,也不用再繼續了。
3、枚舉第k點的時候,如果它前面的點(1 ~ k-1)存在不通電的城市x,並且後面的點(k ~ n)中不存在與x相鄰的點,也不用再繼續了。原因是x這個點(城市)怎麼也不可能通電。它本身不能放發電站(枚舉的就是它不放發電站的情況),其後面的點又不能為它供電。
下面是醜陋的代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 const int N = 40; 8 int n,m; 9 bool Map[N][N];10 int vis[N];11 int s,Min,num;//s是發電站個數,num通電的城市的數量12 void dfs(int cur)13 {14 if(s>Min) return ;//第一種情況的剪枝15 if(cur>n)16 {17 if(num==n) Min=min(Min,s);18 }19 else20 {21 //第三種情況的剪枝22 int i,j;23 for(i=1;i<cur;i++)24 {25 if(!vis[i])26 {27 for(j=cur;j<=n;j++)28 if(Map[i][j]) break;29 if(j>n) return;30 }31 }32 //cur位置放發電站33 int k=num;34 if(!vis[cur]) num++;35 vis[cur]++;36 s++;37 for(i=1;i<=n;i++)38 {39 if(Map[cur][i])40 {41 if(!vis[i]) num++;42 vis[i]++;43 }44 }45 if(num>k) //第二種情況的剪枝46 dfs(cur+1);47 //cur位置不放發電站48 for(i=1;i<=n;i++)49 {50 if(Map[cur][i])51 {52 vis[i]--;53 if(!vis[i]) num--;54 }55 }56 s--;57 vis[cur]--;58 if(!vis[cur]) num--;59 dfs(cur+1);60 }61 }62 int main()63 {64 //freopen("test.txt","r",stdin);65 while(scanf("%d%d",&n,&m)!=EOF&&n)66 {67 memset(vis,0,sizeof(vis));68 memset(Map,0,sizeof(Map));69 int a,b;70 while(m--)71 {72 scanf("%d%d",&a,&b);73 Map[a][b]=Map[b][a]=1;74 }75 Min=35;76 s=0;77 num=0;78 dfs(1);79 printf("%d\n",Min);80 }81 return 0;82 }View Code
PS:感覺剪枝非常需要分析能力。腦袋不夠用了。
UVA10160 Servicing Stations