转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出N个城市,从1开始需要遍历所有点,选择一些点建立加油站,使得花费最少
这题的特殊性在于他的花费上,2^(i-1)
利用一个非常重要的性质,2^0+2^1+2^2……+2^i<2^(i+1)
所有编号<=i的所有点都建,总花费比建一个还少。
这里就贪心一下,先假设所有点都建,然后依次从编号大的删点,看看能不能遍历整个图
dist[i]表示点i距离最近的一个加油站的距离
分析:突破口在于在i号点建立加油站的费用为2^i,这样特殊的花费会使得我们有一个贪心的规律,就是尽量不在号比较大的点建加油站,如果在n号点 建立加油站的费用会大于在除n以外的所有点都建加油站的总费用。所以我们可以先尝试把除n以外的所有点建立加油站,观察是否满足要求。若满足则说明我们必 然不会在n点建立加油站,若不满足我们就一定要在n点建加油站。若需要建,我们就建,然后就不用再考虑n点了,在确定了n点之后,我们用同样的方法来观察 n-1号点是否需要建立加油站,即将1~n-2号点都建立加油站,观察是否满足要求。以此类推,可以推出所有点的情况。
接下来我们需要解决对于一种给定的加油站建立情况,我们如何判断它是否满足题中的travel around的要求。分为两部判断,1.判断所有加油站是否可达(从1号点开始广搜,若到当前点距离<=d则入队)。2.判断其余点是否可达(刚才 的广搜过程可以顺便标出每个点到最近的加油站的距离,要求能从加油站到该点并返回加油站,所以点到加油站的距离必须小于等于d/2)。若满足这两点必然符 合要求,否则不符合要求。
1 #include<iostream> 2 #include<cstdio> 3 #include<map> 4 #include<cstring> 5 #include<cmath> 6 #include<vector> 7 #include<algorithm> 8 #include<set> 9 #include<string> 10 #include<queue> 11 #define inf 1<<30 12 #define M 2005 13 #define N 130 14 #define maxn 300005 15 #define eps 1e-10 16 #define zero(a) fabs(a)<eps 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define Max(a,b) ((a)>(b)?(a):(b)) 19 #define pb(a) push_back(a) 20 #define mp(a,b) make_pair(a,b) 21 #define mem(a,b) memset(a,b,sizeof(a)) 22 #define LL long long 23 #define lson step<<1 24 #define rson step<<1|1 25 #define MOD 1000000009 26 #define sqr(a) ((a)*(a)) 27 #define Key_value ch[ch[root][1]][0] 28 #pragma comment(linker, "/STACK:1024000000,1024000000") 29 using namespace std; 30 struct Point 31 { 32 int x,y; 33 }p[N]; 34 int n,d; 35 int path[N][N]; 36 int ok[N]; 37 double dist(int i,int j) 38 { 39 return sqrt((double)sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y)); 40 } 41 bool bfs() 42 { 43 bool vis[N]; 44 int dist[N]; 45 queue<int>que; 46 mem(vis,false); 47 for(int i=0;i<n;i++) 48 { 49 //本身是加油站,距离是0 50 if(ok[i]) dist[i]=0; 51 else dist[i]=inf; 52 } 53 que.push(0);vis[0]=true; 54 while(!que.empty()) 55 { 56 int u=que.front(); 57 que.pop(); 58 for(int i=0;i<n;i++) 59 { 60 if(!vis[i]&&path[u][i]<=d) 61 { 62 dist[i]=min(dist[i],dist[u]+path[u][i]); 63 if(ok[i]) 64 { 65 que.push(i); 66 vis[i]=true; 67 } 68 } 69 } 70 } 71 for(int i=0;i<n;i++) 72 { 73 //虽然本身是个加油站,但是从1出发根本到不了 74 if(ok[i]&&!vis[i]) return false; 75 //不是一个加油站,不能保证从一个有加油站的地方来回 76 if(!ok[i]&&dist[i]*2>d) return false; 77 } 78 return true; 79 } 80 void slove() 81 { 82 for(int i=0;i<n;i++) ok[i]=1; 83 if(!bfs()) {puts("-1");return ;} //全部都建还不能遍历 84 for(int i=n-1;i>0;i--) 85 { 86 ok[i]=0; 87 if(!bfs()) ok[i]=1; 88 } 89 int j=n-1; 90 while(!ok[j]) j--; 91 for(int i=j;i>=0;i--) printf("%d",ok[i]); 92 puts(""); 93 } 94 int main() 95 { 96 while(scanf("%d%d",&n,&d)!=EOF) 97 { 98 for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); 99 for(int i=0;i<n;i++) 100 { 101 for(int j=0;j<n;j++) 102 { 103 path[i][j]=ceil(dist(i,j)); 104 } 105 } 106 slove(); 107 } 108 return 0; 109 }
原文:http://www.cnblogs.com/cnblogs321114287/p/4436402.html