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("\n");
58    }
59 }
View Code

 

     

posted @ 2013-08-08 12:14  wuminye  阅读(317)  评论(0编辑  收藏  举报