您的位置:首页 > 其它

hdu 4435 charge-station  (贪心+图论)

2013-08-18 21:47 232 查看

charge-station

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 587 Accepted Submission(s): 291



[align=left]Problem Description[/align]
There are n cities in M^3's empire. M^3 owns a palace and a car and the palace resides in city 1. One day, she wants to travel around all the cities from her palace and finally back to her home. However, her car has limited energy
and can only travel by no more than D meters. Before it was run out of energy, it should be charged in some oil station. Under M^3's despotic power, the judge is forced to build several oil stations in some of the cities. The judge must build an oil station
in city 1 and building other oil stations is up to his choice as long as M^3 can successfully travel around all the cities.

Building an oil station in city i will cost 2i-1 MMMB. Please help the judge calculate out the minimum cost to build the oil stations in order to fulfill M^3's will.

[align=left]Input[/align]
There are several test cases (no more than 50), each case begin with two integer N, D (the number of cities and the maximum distance the car can run after charged, 0 < N ≤ 128).

Then follows N lines and line i will contain two numbers x, y(0 ≤ x, y ≤ 1000), indicating the coordinate of city i.

The distance between city i and city j will be ceil(sqrt((xi - xj)2 + (yi - yj)2)). (ceil means rounding the number up, e.g. ceil(4.1) = 5)

[align=left]Output[/align]
For each case, output the minimum cost to build the oil stations in the binary form without leading zeros.

If it's impossible to visit all the cities even after all oil stations are build, output -1 instead.

[align=left]Sample Input[/align]

3 3
0 0
0 3
0 1

3 2
0 0
0 3
0 1

3 1
0 0
0 3
0 1

16 23
30 40
37 52
49 49
52 64
31 62
52 33
42 41
52 41
57 58
62 42
42 57
27 68
43 67
58 48
58 27
37 69


[align=left]Sample Output[/align]

11
111
-1
10111011
Hint
In case 1, the judge should select (0, 0) and (0, 3) as the oil station which result in the visiting route: 1->3->2->3->1. And the cost is 2^(1-1) + 2^(2-1) = 3.


[align=left]Source[/align]
2012 Asia Tianjin Regional Contest

[align=left]Recommend[/align]
zhoujiaqi2010

题意:
n个城市,一个人想从城市1出发,一次访问n个城市再回到城市1。
他的交通工具车在加过油后只能走d米。
可以在各个城市建造加油站,建造费用cost为2^(i-1)
问能使他访问所有城市且回到1点所需要建造加油站的最小花费,以2进制形式输出。

分析:
1、加油站的建造费用太特殊了,是2^(i-1)。之前1到i-1城市的加油站都建的所有花费也比只
建第i个城市的加油站花费小。自己算一下,等比数列求和结果是:(也可以结合二进制来看)
1到i-2个城市都建加油站的花费为 2^(i-1)-1 。(恰好比只建第i个城市的花费小1)
这说明为了使达到目标的花费最小,尽量不要在编号大的城市建加油站。

很容易想到贪心。先假设所有点都建,然后依次从编号大的删点,看看能不能遍历整个图。
dis[i]表示与点i距离最近的加油站的距离。

2、输出的答案是2进制,由费用10进制转化过来就是在第i个点建立加
油站,答案从右往左数第i个值就为1。

3、解题步骤:
(1) 第一步判断所有点都建立加油站能不能完成题目的要求,不能输出-1。

能完成要求的话,我们注意到建站费用是和点的编号有关的,
比如第i个点建站的费用是等于前i-1个点都建站的费用+1,二进制的规律。
然后我们可以从后往前判断当前加油站能不能拆。
(2) dis数组存从当前点到最近的加油站的距离,判断分两个方面:
如果当前点也有加油站,dis[i] <= D就可以;
如果当前点决定不建立加油站,那么dis[i]要小于D/2;
不符合要求就不能拆这个加油站。

感想:开始做的时候1、2两个突破口都没看出来= =!

关于那个从后往前(先把所有的站都建了,再拆)的思路真的是没想到。。。

(处理顺序和题目的突破口,以后解题都要注意~)

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#define INF 1e9
#define sqr(a) ((a)*(a))
using namespace std;

struct node
{
double x,y;
}p[130];
int edge[130][130];
int n,d;
int dis[130],ok[130];
bool vis[130];

double dist(int i,int j)
{
return sqrt((double)sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y));
}
bool bfs()
{
int i;
memset(vis,0,sizeof(vis));
for(i=0;i<n;i++)
{
if(ok[i])
dis[i]=0;    //本身是加油站,则距离是0
else dis[i]=INF;
}
queue<int> q;
q.push(0);
vis[0]=true;
while(!q.empty())
{
int u=q.front();
q.pop();
for(i=0;i<n;i++)
{
if(edge[u][i]<=d&&!vis[i])  //如果能够到达且没访问过
{
dis[i]=min(dis[i],dis[u]+edge[u][i]);  //更新最短距离
if(ok[i])
{
q.push(i);
vis[i]=true;
}
}
}
}
for(i=0;i<n;i++)
{
if(ok[i]&&!vis[i])   //本身是加油站,但是从1出发无法到达
return false;
if(!ok[i]&&dis[i]*2>d)   //本身不是加油站且不能保证从一个有加油站的地方来回
return false;
}
return true;
}
void solve()
{
int i,j;
for(i=0;i<n;i++)
ok[i]=1;
if(!bfs())   //全部都建还不能遍历整个图
{
puts("-1");
return;
}
for(i=n-1;i>0;i--)   //尝试拆掉每个加油站,不能遍历则改回来
{
ok[i]=0;
if(!bfs())
ok[i]=1;
}
j=n-1;
while(!ok[j]) j--;    //去掉前导0
for(i=j;i>=0;i--) printf("%d",ok[i]);
puts("");
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&d)!=EOF)
{
for(i=0;i<n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
edge[i][j]=ceil(dist(i,j));
//printf("test: %d\n",edge[i][j]);
}
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: