码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4435 第37届ACM/ICPC天津现场赛E题

时间:2015-04-18 00:59:04      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:

转载请注明出处,谢谢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 }

 

hdu 4435 第37届ACM/ICPC天津现场赛E题

标签:

原文地址:http://www.cnblogs.com/cnblogs321114287/p/4436402.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!