题意:有一个人要从1点出发把所有点遍历一遍并且最后能回到1点,其中每隔d距离就要加一次油,现在我们在各个点设一些加油站(1点必须设),且每隔点建加油站的费用最小为2^(i-1),求满足条件下的最小花费。
分析:思考了半天也不知道按照什么顺序来搜索,现给出大神思路:
突破口在于在i号点建立加油站的费用为2^(i-1),这样特殊的花费会使得我们有一个贪心的规律,就是尽量不在号比较大的点建加油站,如果在n号点建立加油站的费用会大于在除n以外的所有点都建加油站的总费用。所以我们可以先尝试把除n以外的所有点建立加油站,观察是否满足要求。若满足则说明我们必然不会在n点建立加油站,若不满足我们就一定要在n点建加油站。然后就不用再考虑n点了,在确定了n点之后,我们用同样的方法来观察n-1号点是否需要建立加油站,即将1~n-2号点都建立加油站,观察是否满足要求。以此类推,可以推出所有点的情况。
接下来我们需要解决是否满足要求的问题了。分为两部判断,1.判断所有加油站是否可达(从1号点开始广搜,若到当前点距离<=d则入队)。2.判断其余点是否可达(刚才的广搜过程可以顺便标出每个点到最近的加油站的距离,要求能从加油站到该点并返回加油站,所以点到加油站的距离必须小于等于d/2)。若满足这两点必然符合要求,否则不符合要求。满足要求的话,该点无需建立加油站了。
Orz..................................................................................Orz
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 100005
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std;
int dis[130][130];
int vis[130],x[130],y[130],build[130];
int n,D,flag;
int q[222];
int head,tail;
int getdis(int x1,int y1,int x2,int y2) {
double a1 = x1 * 1.0; double b1 = y1 * 1.0;
double a2 = x2 * 1.0; double b2 = y2 * 1.0;
double s = sqrt((a1-a2)*(a1-a2) + (b1-b2)*(b1-b2));
return ceil(s);
}
void init() {
memset(build,0,sizeof(build));
}
int bfs(int v0) { // 判断除去v0点,其他点能否符合要求
head = 0;
tail = 0;
memset(vis,0,sizeof(vis));
int cnt = 1; //点v0
q[head++] = 1;
vis[1] = 1;
while(head != tail) {
int t = q[tail++];
for(int i=1; i<=n; i++) {
if(vis[i] == 0) {
if(dis[t][i] <= D && (build[i] || i < v0)) {
q[head++] = i;
vis[i] = 1;
cnt ++;
} else {
if(dis[t][i] <= D/2) {
vis[i] = 1;
cnt ++;
}
}
if(cnt == n) return 1;
}
}
}
return 0;
}
int main(){
while(scanf("%d%d",&n,&D) != EOF) {
init();
for(int i=1; i<=n; i++) {
scanf("%d%d",&x[i],&y[i]);
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
dis[i][j] = getdis(x[i],y[i],x[j],y[j]);
}
}
if(bfs(n+1) == 0) { //自己加一个点,则如果已有的n的点不满足要求
printf("-1\n");
continue;
}
for(int i=n; i>1; i--) {
if(bfs(i) == 0) { //i-1个点不满足要求,i点必然要建
build[i] = 1;
}
}
int ok = 0;
for(int i=n; i>1; i--) {
if(build[i] == 1 || ok) {
printf("%d",build[i]);
ok = 1;
}
}
printf("1\n");
}
return 0;
}