zoukankan      html  css  js  c++  java
  • HDU 4435 charge-station

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4435

    题目大意是给出N个二维坐标点代表N个城市,让你选择几个城市建加油站,使得能从1号城市出发遍历所有城市再回来,并且每加一次油的行驶距离为D,不能让车抛锚了。建立一个加油站需要一定的花费,现在要你求花费最少的建站方案。

          题目有个突破口是在第i个城市建加油站的花费是2(i-1),花费刚好就是个N位的二进制,如果在第i位建站,费用比前i-1个城市都建站还高,所以这里可以用贪心,编号越高的城市能不建站就不建站,这样就能保证花费最小。确定能不能建站的方法是如果该城市不建站,从1出发存在一个路径使得能遍历所有城市并返回,则该城市不要建站。所以每确定一个城市要不要建站就需要找一下合法路径。

         由于不需要确切的路径,于是只要判断能否经过所有的点,用类似染色的搜索就可以了,用BFS或DFS都可以。关键是染色的转移条件,如果起点和目标点都没有建站就不能转移,如果两点都建站则要求两点距离<=D,一点建站一点不建站的话要<=D/2;初一看这个规则会把一些情况给漏了,有可能借助一个不建站的B点从一个建站A点到另一个建站C点,这两一进一出有可能有一边的长度大于D/2,且总和不超过D,这样也是满足条件的,但我规则中没涉及这种情况,原因是有替代的方案,虽然不是总路程最优的:既然总和不超D,何不直接从A到C,有一边的距离超过D/2,那必有一边不超过D/2(假设是AB边),按规则来做就是从A到B再回到A加油,这样就和没有B点一样了。如果A、B都是不建站点那没必要现在就判断,应为如果能从A到B再返回一个建站点,那么B一定能直接从建站点过来再回去,在之后的搜索会涉及到。

    我是用DFS来搜索染色的,代码如下。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <math.h>
     4 struct node
     5 {
     6     int x,y;
     7     void read(){scanf("%d%d",&x,&y);}
     8 }data[128];
     9 int n,d,cost[128][128];
    10 bool ifv[128],ans[128];
    11 inline int dist(const node &a,const node &b)
    12 {
    13     return (int)ceil(sqrt((double)((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))));
    14 }
    15 void init()
    16 {
    17     for (int i=0;i<n;++i)
    18       for (int j=0;j<n;++j)
    19       {
    20           cost[i][j]=cost[j][i]=dist(data[i],data[j]);
    21       }
    22 }
    23 int search(int k)
    24 {
    25     int tem=1;
    26     ifv[k]=true;
    27     for (int i=0;i<n;++i)
    28     {
    29         if (i==k || ifv[i] || (!ans[k] && !ans[i]))continue;
    30         if (ans[i] && cost[i][k]<=d && ans[k]) {tem+=search(i);continue;}
    31         if (cost[i][k]<=d>>1) tem+=search(i);
    32     }
    33     return tem;
    34 }
    35 inline bool check()
    36 {
    37     memset(ifv,0,sizeof ifv);
    38     if (search(0)!=n) return false;
    39     return true;
    40 }
    41 int main()
    42 {
    43    while (~scanf("%d%d",&n,&d))
    44    {
    45        memset(ans,true,sizeof ans);
    46        for (int i=0;i<n;++i) data[i].read();
    47        init();
    48        if (!check()) {puts("-1");continue;}
    49        for (int i=n-1;i>0;--i)
    50        {
    51            ans[i]=false;
    52            if (!check()) ans[i]=true;
    53        }
    54        int j=n-1;
    55        while (!ans[j])--j;
    56        while (j>=0) {if (ans[j]) printf("1"); else printf("0");--j;}
    57        printf("
    ");
    58    }
    59 }
    View Code

         

  • 相关阅读:
    每天一个linux命令(1):ls命令
    如何查看和停止Linux启动的服务
    JavaScript作用域原理——作用域根据函数划分
    iOS 自动布局详细介绍
    arc下内存泄漏的解决小技巧
    AFNetwork2.0在报错1016,3840的解决方法及一些感悟
    iOS聊天下拉刷新聊天记录的实现
    tableview直接滚动至最后一行
    UITabBar,UINavigationBar的布局和隐藏问题
    transformjs玩转星球
  • 原文地址:https://www.cnblogs.com/wuminye/p/3245546.html
Copyright © 2011-2022 走看看