1. 程式人生 > 實用技巧 >試題 歷屆試題 郵局(dfs好題)

試題 歷屆試題 郵局(dfs好題)

問題描述   C村住著n戶村民,由於交通閉塞,C村的村民只能通過信件與外界交流。為了方便村民們發信,C村打算在C村建設k個郵局,這樣每戶村民可以去離自己家最近的郵局發信。

  現在給出了m個備選的郵局,請從中選出k個來,使得村民到自己家最近的郵局的距離和最小。其中兩點之間的距離定義為兩點之間的直線距離。 輸入格式   輸入的第一行包含三個整數n, m, k,分別表示村民的戶數、備選的郵局數和要建的郵局數。
  接下來n行,每行兩個整數x, y,依次表示每戶村民家的座標。
  接下來m行,每行包含兩個整數x, y,依次表示每個備選郵局的座標。
  在輸入中,村民和村民、村民和郵局、郵局和郵局的座標可能相同,但你應把它們看成不同的村民或郵局。 輸出格式   輸出一行,包含k個整數,從小到大依次表示你選擇的備選郵局編號。(備選郵局按輸入順序由1到m編號) 樣例輸入 5 4 2
0 0
2 0
3 1
3 3
1 1
0 1
1 0
2 1
3 2 樣例輸出 2 4 資料規模和約定   對於30%的資料,1<=n<=10,1<=m<=10,1<=k<=5;
  對於60%的資料,1<=m<=20;
  對於100%的資料,1<=n<=50,1<=m<=25,1<=k<=10。 題解: 需要的資料,居民座標,郵局座標,每個居民到所有郵局的距離range。 維護一個居民到最近的郵局距離的陣列length,如果有邊有更新,證明該郵局可選。 每個郵局都有選和不選,兩種選擇,分別進行dfs。 當已選定k個郵局時比較總距離是否有減小,有的話進行更新,儲存郵局的序號用一個vector即可。 直接暴力只能得到80分,需要做一些剪枝。 1.當到第pos個郵局時,後面所有的郵局全選的情況仍不滿足條件,可直接跳出。 2.當第pos個郵局無法鬆弛距離,做一個標記,之後只走不選擇的那條路。
#include<bits/stdc++.h>
using
namespace std; struct node{ int x, y; }host[55],post[55]; int n,m,k; double lenth[55],range[55][55],vis[55]; const int inf=0x3f3f3f; double maxx=0x3f3f3f; vector<int>vex; void dfs(int pos,double sum,int num,vector<int>v){ if(num+m-pos+1<k)return ;///pruning if(num==k){
if(sum<maxx){ maxx=sum; vex=v; } return ; } dfs(pos+1,sum,num,v);///not to bulid if(vis[pos])return ; double temp[55]; memcpy(temp,lenth,sizeof(temp));///temp object int flag=0; for(int j=1;j<=n;j++){ if(range[pos][j]<lenth[j]){///update lenth[j]=range[pos][j]; flag=1; } } sum=0; for(int k=1;k<=n;k++){ sum+=lenth[k]; } if(flag){///bulid v.push_back(pos); dfs(pos+1,sum,num+1,v); v.pop_back(); memcpy(lenth,temp,sizeof(lenth));///fight off the effect } else vis[pos]=1; } double dis(node a,node b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++){ scanf("%d%d",&host[i].x,&host[i].y); } for(int i=1;i<=m;i++){ scanf("%d%d",&post[i].x,&post[i].y); for(int j=1;j<=n;j++){ range[i][j]=dis(post[i],host[j]); } } for(int i=1;i<=n;i++){ lenth[i]=inf; } dfs(1,0,0,vex); sort(vex.begin(),vex.end()); for(vector<int>::iterator it=vex.begin();it!=vex.end();it++){ cout<<*it<<" "; } return 0; }